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

来源:互联网 发布:linux i2c总线驱动 编辑:程序博客网 时间:2024/06/05 00:30

什么是工厂方法?

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)。

如下图所示,是工厂方法的类结构图:QQ20130516-4

什么时候使用工厂方法?

当是如下情况是,可以使用工厂方法:

  1. 一个类不知道它所必须创建的对象的类时
  2. 一个类希望有它的子类决定所创建的对象时

更多关于工厂方法的介绍,可以参考本文最后给出的参考内容。下面我们就来看看在iOS中工厂方法的一种实现方法。

iOS中工厂方法的实现

如下有一个类图,该图描述了下面即将实现的工厂方法(利用工厂方法,创建出不同的形状)。其中BVShapeFactory为工厂方法的基类,BVShape为形状的基类,BVClient通过BVShapeFactory,利用 BVShapeFactory的子类(BVCircleShapeFactory和BVSquareShapeFactory)分别创建出BVCircleShape和BVSquareShape。

factory-method-pattern

如下图,是在Xcode中创建的相关文件

QQ20130516-5

具体实现步骤如下(建议下载本文最后给出的代码实例,用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中做了特殊处理,具体内容可以看上面的代码,已经有注视了。

  1. 子类化形状基类

首先子类化一个圆形类: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
  1.  创建一个工厂方法的基类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,该类的子类必须实现该方法,通过实现该方法,返回一个具体的形状对象。下面来看看该类的子类化。

  1. 子类化工厂方法的基类

首先子类化一个圆形工厂方法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实例。

  1. 工厂方法的使用

定义一个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方法进行测试。会在控制台窗口输出如下内容:

  1. 2013-05-16 10:12:46.292 FactoryMethodPattern[2845:c07] 绘制一个BVCircleShape图形
  2. 2013-05-16 10:12:46.295 FactoryMethodPattern[2845:c07] 绘制一个BVSquareShape图形

代码实例

本文涉及到的相关实例代码和PDF归档可以到点击下图下载:

代码下载            pdf-icon

参考

在学习工厂方法时,参考了如下一些文章和视频:

工厂方法wiki上对工厂方法的介绍
Class Factory Methods 苹果官网对类工厂方法的介绍
iOS Patterns. Factory Method(一篇介绍工厂方法的文章,俄文,需要楼梯)
What Is the Factory Method Pattern?(Pro Objective-C Design Patterns for iOS书中对工厂方法的介绍)
.NET设计模式(5):工厂方法模式(Factory Method)
java实现工厂方法
JAVA: Factory Method Design Patternyoutube上一个关于工厂方法的视频介绍
iphone-sdk-difference-between-iskindofclass-and-ismemberofclass iskindofclass和ismemberofclass区别