定义
抽象工厂:提供了一个创建一系列相关或者相互依赖对象的接口,而无需指定他们具体的类。
抽象工厂与工厂方法的区别
| 抽象工厂 | 工厂方法 |
|---|---|
| 通过对象组合创建抽象产品 | 通过类继承创建抽象产品 |
| 创建多系列产品 | 创建一种产品 |
| 必须修改父类的接口才能支持新的产品 | 子类化创建者重载工厂方法来创建新产品 |
两个方法的相同目的为:创建对象而不让客户端知晓返回了什么确切的具体对象。
使用场景
使用抽象工厂模式的场景如下:
- 需要创建一系列有关联的对象
搭配其他模式
- 原型模式
- 单例模式
- 享元模式
类图结构
抽象工厂方法类图结构如下:

AbstractFactory将创建Product的实现细节隐藏在具体子类ConcreateFactory中。这种方案下,将来需要新增类型时,通过添加ConcreateFactory和Product即可实现。
代码实现
实现如下需求,在项目中,针对视图View,按钮button,以及功能区toorbar,进行Acme与Seirra两个品牌定制化显示,后续可能会增加其他品牌。 我们先实现抽象父类BrandFactory如下:
@interface BrandFactory : NSObject
+ (BrandFactory *)factory;
- (UIView *)brandView;
- (UIButton *)brandMainButton;
- (UIToolbar *)brandToorbar;
@end
@implementation BrandFactory
+ (BrandFactory *)factory{
#ifdef USER_ACME
return [AcmeBrandingFactory new];
#elifdef USER_SIERRA
return [SierraBrandingFactory new];
#else
return nil;
#endif
}
- (UIView *)brandView{return nil;}
- (UIButton *)brandMainButton{return nil;}
- (UIToolbar *)brandToorbar{return nil;}
@end
factory类方法中,根据项目的宏定义不同,返回不同的品牌子类。无需设计在运行时决定使用什么工厂的复杂机制。通过简单的预处理定义,完全在编译时决定,过程中不涉及其他类,否则,增加其他类会增加应用程序的复杂度。
定义各类品牌子视图的创建方法,在类实现中默认返回nil,由子类AcmeBrandingFactory与SierraBrandingFactory重载这些方法,返回品牌化特征的具体产品。
@interface AcmeBrandingFactory : BrandFactory
- (UIView *)brandView;
- (UIButton *)brandMainButton;
- (UIToolbar *)brandToorbar;
@end
@implementation AcmeBrandingFactory
- (UIView *)brandView{
return [AcmeView new];
}
- (UIButton *)brandMainButton{
return [AcmeButton new];
}
- (UIToolbar *)brandToorbar{
return [AcmeToorbar new];
}
@end
@interface SierraBrandingFactory : BrandFactory
- (UIView *)brandView;
- (UIButton *)brandMainButton;
- (UIToolbar *)brandToorbar;
@end
@implementation SierraBrandingFactory
- (UIView *)brandView{
return [SierraView new];
}
- (UIButton *)brandMainButton{
return [SierraButton new];
}
- (UIToolbar *)brandToorbar{
return [SierraToorbar new];
}
@end
AcmeBrandingFactory与SierraBrandingFactory都继承自相同的父类BrandFactory,并且重载实现brandView,brandMainButton,brandToorbar这些具体产品的创建方法,返回不同品牌特征的对应视图
在子类工厂的声明中,也重复声明了重载的父类方法,这是个好习惯,可以很明确的告诉外界,自己重载了父类的那些方法,明确定义了自己的具体实现。
当需要支持额外的一个品牌时,只需增加一个子类工厂与具体的产品实现即可。
下面我们来看一下如何调用该工厂方法创建具体的子类
- (void)loadView{
BrandFactory *factory = [BrandFactory factory];
[self.view addSubview:[factory brandView]];
[self.view addSubview:[factory brandMainButton]];
[self.view addSubview:[factory brandToorbar]];
}
在使用的ViewController的loadView方法中,根据定义不同返回对应的BrandFactory,然后使用工厂类生成不同的产品视图添加到当前视图中。
抽象工厂在Cocoa Touch中的使用
抽象工厂模式常见于Cocoa Touch框架中,例如NSNumber,NSArray,NSDictionary,NSString,以及NSData。这种实现方式我们也称之为类簇。
类簇是基础框架中一种常见的设计模式,基于抽象工厂模式的思想。将若干相关的私有具体工厂子类集合到一个工友的抽象超类之下,典型的就是NSNumber。NSNumber本身就是一个高度抽象的工厂,而NSCFBoolean和NSCFNumber是具体工厂子类。根据下面的类工厂方法返回不同的工厂子类
+ (NSNumber *)numberWithChar:(char)value;
+ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
+ (NSNumber *)numberWithShort:(short)value;
+ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
+ (NSNumber *)numberWithInt:(int)value;
+ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
...
子类都会实现超类中如下的实现以完成统一的方法返回
@property (readonly) int intValue;
@property (readonly) BOOL boolValue;
@property (readonly, copy) NSString *stringValue;
- (NSComparisonResult)compare:(NSNumber *)otherNumber;
- (BOOL)isEqualToNumber:(NSNumber *)number
注意点: 如果有多个工厂类有共同的行为,则需要使用抽象父类,实现相同的行为,如没有相同的行为,则可以使用协议protocol来代替抽象父类,使代码更加解耦。
总结
一系列相关类的好的模式,应该作为一种抽象,不为客户端所见。抽象工厂可以顺畅的提供这种抽象,而不暴露创建过程中任何不必要的细节或者创建对象的确切类型。
软件设计的黄金法则:变动需要抽象