iOS中的设计模式——生成器(Builder)
18 Sep 2016
生成器模式
生成器模式(Builder):将一个复杂对象的构建与它的表现分离,使得同样的构建过程可以创建不同的表现。
有时,构建某些对象有多种不同方式。如果这些逻辑包含在构建这些对象的类的单一方法中,代码将会充满条件判断。如果能把构建过程分解为客户-指导者-生成器(client-director-builder)的关系,那么过程将更容易管理与服用。针对此类关系的设计模式成为生成器。
类图

Builder是一个抽象接口,声明了一个buildPart方法,该builder方法由ConcreteBuilder实现,以构造实际产品(Product)。ConcreteBuilder有个getResult方法,向客户端返回构造完毕的Product。Director定义了一个construct方法,命令Builder的实例去buildPart。Director和Builder形成一种聚合关系。这意味着Builder是一个组成部分,与Director结合,以使整个模式运转,但同时,Director并不负责Builder的生命周期。这种“整体-部分”的关系用下图时序图表示:

aClient生成ConcreteBuilder的实例(aConcreteBuilder)和以aConcreteBuilder为初始化参数的Director的实例(aDirector),用于今后协同工作。当aClient发送construct消息给aDirector时,该方法发送要建造什么消息(比如builderPartA、builderPartB和builderPartC)给aConcreteBuilder。aDirector的construct方法返回后,aClient直接向aConcreteBuilder发送getResult消息,取回建造完毕的产品。所以aDirector所知的“什么”,就是每个Builder能够建造什么部件。
使用场景
-
需要创建设计各种部件的复杂对象。创建对象的算法应该独立于部件的装配方式。常见的例子是构建组合对象。
-
构建过程需要以不同的方式(例如,部件或表现的不同组合)构建对象。
生成器与抽象工厂的对比
两者有相似之处。但是,一方面生成器关注的是分步创建复杂对象,很多时候同一类型的对象可以以不同的方式创建。另一方面,抽象工厂的重点在于创建简单或复杂产品的套件,生成器在多步创建过程的最后一步返回产品,而抽象工厂会立即返回产品。
| 生成器 | 抽象工厂 |
|---|---|
| 构建复杂对象 | 构件简单或复杂对象 |
| 以多个步骤构建对象 | 以单一步骤构建对象 |
| 以多种方式构建对象 | 以单一方式构建对象 |
| 在构建过程的最后一步返回产品 | 立刻返回产品 |
| 专注一个特定产品 | 强调一套产品 |
使用方式
我们定义一个叫ChasingGame的类,它有两个方法,用于创建两种类型的角色——游戏玩家与敌人。CharacterBuilder用于构建角色,每个属性都会影响被构建角色的特性。显示其静态关系的类图如下:

CharacterBuilder为抽象生成器,StandardCharacterBuilder为具体生成器,ChasingGame为指导者。
ChasingGame定义了createPalyer:builder和createEnemy:builder,通过CharacterBuilder的实例创建游戏玩家和敌人角色。每个方法有一套不同的特征因子,用来定义角色的特性。StandardCharacterBuilder是具体的CharacterBuilder,它根据不同特征因子实际构建角色。构建过程结束后,StandardCharacterBuilder将返回Character的实例。
//Character.h
@interface Character : NSObject
@property (nonatomic, assign) float protection;//防御
@property (nonatomic, assign) float power;//攻击
@property (nonatomic, assign) float strength;//力量
@property (nonatomic, assign) float stamina;//耐力
@property (nonatomic, assign) float intelligence;//智利
@property (nonatomic, assign) float agility;//敏捷
@property (nonatomic, assign) float aggressiveness;//攻击力
@end
//Character.m
@implementation Character
- (instancetype)init {
self = [super init];
if (self) {
self.protection = 1.f;
self.power = 1.f;
self.strength = 1.f;
self.stamina = 1.f;
self.intelligence = 1.f;
self.agility = 1.f;
self.aggressiveness = 1.f;
}
return self;
}
@end
Character的实例不知道如何把自己构建成有意义的角色,所以才需要CharacterBuilder基于先前定义的特征关系,构建有意义的角色。
//CharacterBuilder.h
@interface CharacterBuilder : NSObject
@property (nonatomic, strong) Character *character;
- (CharacterBuilder *)buildNewChapteracter;
- (CharacterBuilder *)buildStrength:(float)value;
- (CharacterBuilder *)buildStamina:(float)value;
- (CharacterBuilder *)buildIntelligence:(float)value;
- (CharacterBuilder *)buildAgility:(float)value;
- (CharacterBuilder *)buildAggressiveness:(float)value;
@end
CharacterBuilder的实例有个对目标Character的引用,该目标Character构建完成后将被返回给客户端。有几个构建角色的方法,构建的角色具有特定的力量、耐力、智力、敏捷与攻击力值。这些值影响防御和攻击因子。抽象的CharacterBuilder定义了默认行为,他把这些值设定给目标Character。
//CharacterBuilder.m
@implementation CharacterBuilder
- (CharacterBuilder *)buildNewChapteracter {
self.character = [[Character alloc] init];
return self;
}
- (CharacterBuilder *)buildStrength:(float)value {
self.character.strength = value;
return self;
}
- (CharacterBuilder *)buildStamina:(float)value {
self.character.stamina = value;
return self;
}
- (CharacterBuilder *)buildIntelligence:(float)value {
self.character.intelligence = value;
return self;
}
- (CharacterBuilder *)buildAgility:(float)value {
self.character.agility = value;
return self;
}
- (CharacterBuilder *)buildAggressiveness:(float)value {
self.character.aggressiveness = value;
return self;
}
@end
CharacterBuilder的buildNewChapteracter方法生成要构建的Character新实例。StandardCharacterBuilder是CharacterBuilder的子类,定义了生成具有各种相关特性的真正角色的逻辑。
//StandardCharacterBuilder.h
@interface StandardCharacterBuilder : CharacterBuilder
- (CharacterBuilder *)buildStrength:(float)value;
- (CharacterBuilder *)buildStamina:(float)value;
- (CharacterBuilder *)buildIntelligence:(float)value;
- (CharacterBuilder *)buildAgility:(float)value;
- (CharacterBuilder *)buildAggressiveness:(float)value;
@end
//StandardCharacterBuilder.m
@implementation StandardCharacterBuilder
- (CharacterBuilder *)buildStrength:(float)value {
self.character.protection *= value;//更新角色的防御值
self.character.power *= value;//更新角色的攻击值
return [super buildStrength:value];//设定力量并返回此生成器
}
- (CharacterBuilder *)buildStamina:(float)value {
self.character.protection *= value;//更新角色的防御值
self.character.power *= value;//更新角色的攻击值
return [super buildStamina:value];//设定耐力并返回此生成器
}
- (CharacterBuilder *)buildIntelligence:(float)value {
self.character.protection *= value;//更新角色的防御值
self.character.power /= value;//更新角色的攻击值
return [super buildIntelligence:value];//设定智力并返回此生成器
}
- (CharacterBuilder *)buildAgility:(float)value {
self.character.protection *= value;//更新角色的防御值
self.character.power /= value;//更新角色的攻击值
return [super buildAgility:value];//设定敏捷并返回此生成器
}
- (CharacterBuilder *)buildAggressiveness:(float)value {
self.character.protection /= value;//更新角色的防御值
self.character.power *= value;//更新角色的攻击值
return [super buildAgility:value];//设定攻击力并返回此生成器
}
@end
//ChasingGame.h
@interface ChasingGame : NSObject
- (Character *)createPlayer:(CharacterBuilder *)builder;
- (Character *)createEnemy:(CharacterBuilder *)builder;
@end
//ChasingGame.m
@implementation ChasingGameß
- (Character *)createPlayer:(CharacterBuilder *)builder {
[builder buildNewChapteracter];
[builder buildStrength:50.0];
[builder buildStamina:25.0];
[builder buildIntelligence:75.0];
[builder buildAgility:65.0];
[builder buildAggressiveness:35.0];
return [builder character];
}
- (Character *)createEnemy:(CharacterBuilder *)builder {
[builder buildNewChapteracter];
[builder buildStrength:80.0];
[builder buildStamina:65.0];
[builder buildIntelligence:35.0];
[builder buildAgility:25.0];
[builder buildAggressiveness:95.0];
return [builder character];
}
@end
客户端生成StandardCharacterBuilder和ChasingGame实例。然后向ChasingGame发送createPlayer:和createEnemy:消息。
ChasingGame *game = [[ChasingGame alloc] init];
CharacterBuilder *characterBuilder = [[StandardCharacterBuilder alloc] init];
Character *player = [game createPlayer:characterBuilder];
Character *enemy = [game createEnemy:characterBuilder];
NSLog(@"%@", player);
NSLog(@"%@", enemy);
总结
生成器模式能够帮助构建涉及部件与表现的各种组合的对象。没有这一模式,知道构建对象所需细节的Director可能最终变成一个庞大的类,带有无数用于构建同一个类的各种表现得内嵌算法。设计具有各种特征的角色的游戏,应该好好使用这一模式。不是定义单独的Director去构建游戏玩家和敌人,而是把角色构建算法放在一个具体CharacterBuilder中,是更优雅的做法。
代码
文章中的代码都可以从我的GitHub DesignPatterns找到。