iOS设计模式(03):工厂方法

发布于:2013-05-16 11:11阅读数:

什么是工厂方法?在基类中定义创建对象的一个接口,让子类决定实例化哪个类。工厂方法让一个类的实例化延迟到子类中进行。工厂方法要解决的问题是对象的创建时机,它提供了一种扩展的

 什么是工厂方法?

 
GOF是这样描述工厂模式的:
“Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.”
 
在基类中定义创建对象的一个接口,让子类决定实例化哪个类。工厂方法让一个类的实例化延迟到子类中进行。
 
工厂方法要解决的问题是对象的创建时机,它提供了一种扩展的策略,很好地符合了开放封闭原则。工厂方法也叫做虚构造器(Virtual Constructor)。
 
如下图所示,是工厂方法的类结构图:
 
什么时候使用工厂方法?
当是如下情况是,可以使用工厂方法:一个类不知道它所必须创建的对象的类时,一个类希望有它的子类决定所创建的对象时。
 
更多关于工厂方法的介绍,可以参考本文最后给出的参考内容。下面我们就来看看在iOS中工厂方法的一种实现方法。
 
iOS中工厂方法的实现
如下有一个类图,该图描述了下面即将实现的工厂方法(利用工厂方法,创建出不同的形状)。其中BVShapeFactory为工厂方法的基类,BVShape为形状的基类,BVClient通过BVShapeFactory,利用 BVShapeFactory的子类(BVCircleShapeFactory和BVSquareShapeFactory)分别创建出BVCircleShape和BVSquareShape。
 
如下图,是在Xcode中创建的相关文件
 
 
(具体实现步骤如下(建议下载本文最后给出的代码实例,用Xcode查阅代码):
 
1.创建一个形状基类BVShape。该类中定义了形状的基本行为和属性,如下代码所示:
 
BVShape.h
1.//
2.//  BVShape.h
3.//  FactoryMethodPattern
4.//
5.//  Created by BeyondVincent on 13-5-15.
6.//  Copyright (c) 2013年 BeyondVincent. All rights reserved.
7.//
8. 
9.#define BV_Exception_Format @"在%@的子类中必须override:%@方法"
10. 
11.@interface BVShape : NSObject
12. 
13.@property (nonatomic, weak)NSString *name;
14. 
15.// 子类必须重写这个draw方法,否则会抛出异常错误
16.-(void)draw;
17. 
18.@end
 
BVShape.m
1.//
2.//  BVShape.m
3.//  FactoryMethodPattern
4.//
5.//  Created by BeyondVincent on 13-5-15.
6.//  Copyright (c) 2013年 BeyondVincent. All rights reserved.
7.//
8. 
9.#import "BVShape.h"
10. 
11.@implementation BVShape
 12.
13.-(id)init
14.{
15.  self = [super init];
16.    if (self) {
17.        // 做一些初始化任务
18.    }
19.    return self;
20.}
21. 
22.-(void)draw
23.{
24.    // 如果是通过BVShape的实例调用此处的draw,则绘制一个BVShape图形
25.    if ([self isMemberOfClass:[BVShape class]]) {
 26.       NSLog(@"绘制一个BVShape图形");
27.    } else {
28.        // 如果是通过BVShape子类的实例调用了此处的draw,则抛出一个异常:表明子类并没有重写draw方法。
29.        // 注:在OC中并没有abstract class的概念,只有protocol,如果在基类中只定义接口(没有具体方法的实现),
30.        //    则可以使用protocol,这样会更方便。 
31.        [NSException raise:NSInternalInconsistencyException
32.                    format:BV_Exception_Format, [NSString stringWithUTF8String:object_getClassName(self)], NSStringFromSelector(_cmd)];
33.    }
34.}
35. 
36.@end
 
 
在上面的代码中定义了一个draw方法,为了让子类必须实现该方法,在BVShape中做了特殊处理,具体内容可以看上面的代码,已经有注视了。
 
2.子类化形状基类。首先子类化一个圆形类:BVCircleShape。
BVCircleShape.h
1.//
2.//  BVCircleShape.h
3.//  FactoryMethodPattern
4.//
5.//  Created by BeyondVincent on 13-5-15.
6.//  Copyright (c) 2013年 BeyondVincent. All rights reserved.
7.//
8. 
9.#import "BVShape.h"
10. 
11.@interface BVCircleShape : BVShape
12. 
13.@end
 
BVCircleShape.m
1.//
2.//  BVCircleShape.m
3.//  FactoryMethodPattern
4.//
5.//  Created by BeyondVincent on 13-5-15.
6.//  Copyright (c) 2013年 BeyondVincent. All rights reserved.
7.//
8. 
9.#import "BVCircleShape.h"
 10.
11.@implementation BVCircleShape
12. 
13.-(void)draw
14.{
15.    NSLog(@"绘制一个BVCircleShape图形");
16.}
17. 
18.@end
 
 
在上面的子类中,重写了基类的draw方法。同样,我们再子类化一个正方形类,并重写draw方法,如下代码所示:
BVSquareShape.h
1.//
2.//  BVSquareShape.h
3.//  FactoryMethodPattern
4.//
5.//  Created by BeyondVincent on 13-5-15.
6.//  Copyright (c) 2013年 BeyondVincent. All rights reserved.
7.//
8. 
9.#import "BVShape.h"
10. 
11.@interface BVSquareShape : BVShape
 12.
13.@end
 
BVSquareShape.m
1.//
2.//  BVSquareShape.m
3.//  FactoryMethodPattern
4.//
5.//  Created by BeyondVincent on 13-5-15.
6.//  Copyright (c) 2013年 BeyondVincent. All rights reserved.
7.//
8. 
9.#import "BVSquareShape.h"
10.
11.@implementation BVSquareShape
12. 
13.-(void)draw
14.{
15.    NSLog(@"绘制一个BVSquareShape图形");
16.}
17. 
18.@end
 
3.创建一个工厂方法的基类BVShapeFactory
BVShapeFactory.h
1.//
2.//  BVShapeFactory.h
3.//  FactoryMethodPattern
4.//
5.//  Created by BeyondVincent on 13-5-15.
6.//  Copyright (c) 2013年 BeyondVincent. All rights reserved.
7.//
8. 
9.#import "BVShape.h"
10. 
11.@interface BVShapeFactory : NSObject
12. 
13.-(BVShape *) factoryMethod;
14. 
15.@end
 
BVShapeFactory.m
1.//
2.//  BVShapeFactory.m
3.//  FactoryMethodPattern
4.//
5.//  Created by BeyondVincent on 13-5-15.
6.//  Copyright (c) 2013年 BeyondVincent. All rights reserved.
7.//
8. 
9.#import "BVShapeFactory.h"
10. 
11.@implementation BVShapeFactory
12. 
13.-(BVShape *)factoryMethod
14.{
15.    // 在此处,子类必须重写factoryMethod方法。当然,在工厂模式中,也可以在此处返回一个默认的Product。
16.    // 如果是通过BVShapeFactory子类的实例调用了此处的factoryMethod,则抛出一个异常:表明子类并没有重写factoryMethod方法。
17.    [NSException raise:NSInternalInconsistencyException
18.                format:BV_Exception_Format, [NSString stringWithUTF8String:object_getClassName(self)], NSStringFromSelector(_cmd)];
19. 
20.    // 下面这个return语句只是为了消除警告,实际上永远都不会执行到这里。
21.    return nil;
22.}
23. 
24.@end
 
在上面的代码中,定义了一个factoryMethod,该类的子类必须实现该方法,通过实现该方法,返回一个具体的形状对象。下面来看看该类的子类化。
 
4.子类化工厂方法的基类。首先子类化一个圆形工厂方法BVCircleShapeFactory:
BVCircleShapeFactory.h
1.//
2.//  BVCircleShapeFactory.h
3.//  FactoryMethodPattern
4.//
5.//  Created by BeyondVincent on 13-5-15.
6.//  Copyright (c) 2013年 BeyondVincent. All rights reserved.
7.//
 8.
9.#import "BVShapeFactory.h"
10.#import "BVCircleShape.h"
11. 
12.@interface BVCircleShapeFactory : BVShapeFactory
13. 
14.@end
 
BVCircleShapeFactory.m
1.//
2.//  BVCircleShapeFactory.m
3.//  FactoryMethodPattern
4.//
5.//  Created by BeyondVincent on 13-5-15.
6.//  Copyright (c) 2013年 BeyondVincent. All rights reserved.
7.//
8. 
9.#import "BVCircleShapeFactory.h"
 10.
11.@implementation BVCircleShapeFactory
12. 
13.-(BVShape *)factoryMethod
14.{
15.    return [[BVCircleShape alloc] init];
16.}
17. 
18.@end
 
如上代码所示,重写了factoryMethod,返回一个BVCircleShape实例。下面来看看另外一个子类BVSquareShapeFactory
BVSquareShapeFactory.h
1.//
2.//  BVSquareShapeFactory.h
3.//  FactoryMethodPattern
4.//
5.//  Created by BeyondVincent on 13-5-15.
6.//  Copyright (c) 2013年 BeyondVincent. All rights reserved.
7.//
8. 
9.#import "BVShapeFactory.h"
10.#import "BVSquareShape.h"
11. 
12.@interface BVSquareShapeFactory : BVShapeFactory
13. 
14.@end
 
BVSquareShapeFactory.m
1.//
2.//  BVSquareShapeFactory.m
3.//  FactoryMethodPattern
4.//
5.//  Created by BeyondVincent on 13-5-15.
6.//  Copyright (c) 2013年 BeyondVincent. All rights reserved.
7.//
8. 
9.#import "BVSquareShapeFactory.h"
10. 
11.@implementation BVSquareShapeFactory
12. 
13.-(BVShape *)factoryMethod
14.{
15.    return [[BVSquareShape alloc] init];
16.}
17. 
18.@end
 
该子类返回的是一个BVSquareShape实例。
 
5.工厂方法的使用。定义一个BVClient类,在该类中演示工厂方法的使用。代码如下:
BVClient.h
1.//
2.//  BVClient.h
3.//  FactoryMethodPattern
4.//
5.//  Created by BeyondVincent on 13-5-15.
6.//  Copyright (c) 2013年 BeyondVincent. All rights reserved.
7.//
8. 
9.@interface BVClient : NSObject
 10.
11.-(void)doSomething;
12. 
13.@end
 
BVClient.m
1.//
2.//  BVClient.m
3.//  FactoryMethodPattern
4.//
5.//  Created by BeyondVincent on 13-5-15.
6.//  Copyright (c) 2013年 BeyondVincent. All rights reserved.
7.//
8. 
9.#import "BVClient.h"
10. 
11.#import "BVShapeFactory.h"
12.#import "BVCircleShapeFactory.h"
13.#import "BVSquareShapeFactory.h"
14. 
15.#import "BVShape.h"
16.#import "BVCircleShape.h"
17.#import "BVSquareShape.h"
18. 
19.@implementation BVClient
 20.
21.-(void)doSomething
22.{
23.    // 工厂方法的实例化
24.    BVShapeFactory *circleShapefactory = [[BVCircleShapeFactory alloc] init];
25.    BVShapeFactory *squareShapefactory = [[BVSquareShapeFactory alloc] init];
26. 
27.    // 通过工厂方法实例化对应的形状
28.    BVShape *circleShape = [circleShapefactory factoryMethod];
29.    BVShape *squareShape = [squareShapefactory factoryMethod];
30. 
31.    // 调用形状的方法
32.    [circleShape draw];
33.    [squareShape draw];
34.}
35. 
36.@end
 
如上代码所示,首先实例化两个工厂方法,并通过工厂方法创建出对应的形状,最后调用形状的draw方法进行测试。会在控制台窗口输出如下内容:
2013-05-16 10:12:46.292 FactoryMethodPattern[2845:c07] 绘制一个BVCircleShape图形
2013-05-16 10:12:46.295 FactoryMethodPattern[2845:c07] 绘制一个BVSquareShape图形
 

本文涉及到的相关实例代码:github下载地址

来源:破船的博客

CocoaChina是全球最大的苹果开发中文社区,官方微信每日定时推送各种精彩的研发教程资源和工具,介绍app推广营销经验,最新企业招聘和外包信息,以及Cocos2d引擎、Cocos Studio开发工具包的最新动态及培训信息。关注微信可以第一时间了解最新产品和服务动态,微信在手,天下我有!

请搜索微信号“CocoaChina”关注我们!

搜索CocoaChina微信公众号:CocoaChina

顶部