前言
选择建造自己房子的人会把工程外包给承包商。单一承包商不能建造整个房子,他将其分解为几个部分,然后转包给几个实际的建筑商。客户告诉承包商房子里都有什么,然后承包商协调指导各房屋建筑商,决定需要做什么,应该如何建造。将建造过程分解为 客户-指导者(承包商)- 建造者(建筑商)的关系,过程更容易管理与复用,针对此类关系的设计模式称为建造者模式。
什么是建造者模式
有时,构建某些对象有多种不同方式,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。将一个复杂对象的构建与它的表现分离,使得同样的构建过程可以创建不同的表现。建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。
传统建造者模式有4个角色。
-
Product
: 最终要生成的对象 -
Builder
: 构建者的抽象基类(有时会使用协议代替)。其定义了构建Product
的抽象步骤,其实体类需要实现这些步骤。其会包含一个用来返回最终产品的方法Product getProduct()
。 -
ConcreteBuilder
:Builder
的实现类。 -
Director
: 决定如何构建最终产品的算法. 其会包含一个负责组装的方法void Construct(Builder builder)
, 在这个方法中通过调用builder
的方法,就可以设置builder
,等设置完成后,就可以通过builder的getProduct()
方法获得最终的产品。
什么时候使用建造者模式
一些基本部件不会变,而其组合经常变化的时候,构建需要以不同的方式构建对象
需要生成的对象具有复杂的内部结构
需要生成的对象内部属性本身相互依赖。
建造者模式的优缺点
优点
- 建造者独立,易扩展。
- 便于控制细节风险。
缺点
- 产品必须有共同点,范围有限制。
- 如内部变化复杂,会有很多的建造类。
建造者与抽象工厂的对比
建造者 | 抽象工厂 |
---|---|
构建复杂对象 | 构建简单或复杂对象 |
以多个步骤构建对象 | 以单一步骤构建对象 |
以多种方式构建对象 | 以单一方式构建对象 |
在构建过程的最后一步返回产品 | 立刻返回产品 |
专注一个特定产品 | 强调一套产品 |
建造者模式的实现
以假想的游戏角色为例,假定有两个类型的角色——敌人和游戏者,角色具有共同的基本特征,如力量,耐力,智力、敏捷和攻击力。每一个特征都影响着角色的防御(protection)和攻击(Power)能力,因此我们定义一个角色类 Character
:
@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
@implementation Character
- (instancetype)init
{
self = [super init];
if (self) {
_protection = 1.0;
_power = 1.0;
_strength = 1.0;
_stamina = 1.0;
_intelligence = 1.0;
_agility = 1.0;
_aggressiveness = 1.0;
}
return self;
}
@end
接着,我们定义抽象的角色构建者 CharacterBuilder
:
@interface CharacterBuilder : NSObject
{
@protected
Character *_character;
}
@property (nonatomic, readonly) Character *character;
- (CharacterBuilder *) buildNewCharacter;
- (CharacterBuilder *) buildStrength:(float) value;
- (CharacterBuilder *) buildStamina:(float) value;
- (CharacterBuilder *) buildIntelligence:(float) value;
- (CharacterBuilder *) buildAgility:(float) value;
- (CharacterBuilder *) buildAggressiveness:(float) value;
@end
@implementation CharacterBuilder
@synthesize character=_character;
- (CharacterBuilder *) buildNewCharacter
{
_character = [[Character alloc] init];
return self;
}
- (CharacterBuilder *) buildStrength:(float) value
{
_character.strength = value;
return self;
}
- (CharacterBuilder *) buildStamina:(float) value
{
_character.stamina = value;
return self;
}
- (CharacterBuilder *) buildIntelligence:(float) value
{
_character.intelligence = value;
return self;
}
- (CharacterBuilder *) buildAgility:(float) value
{
_character.agility = value;
return self;
}
- (CharacterBuilder *) buildAggressiveness:(float) value
{
_character.aggressiveness = value;
return self;
}
@end
StandardCharacterBuilder
是具体的 CharacterBuilder
。在这里,力量和耐力与防御和攻击成正比,智力和敏捷与防御成正比,与攻击成反比。根据不同特征因子实际构建角色。构建过程结束后,StandardCharacterBuilder
将返回 Character
的实例。
@interface StandardCharacterBuilder : CharacterBuilder
{
}
// overriden methods from the abstract CharacterBuilder
- (CharacterBuilder *) buildStrength:(float) value;
- (CharacterBuilder *) buildStamina:(float) value;
- (CharacterBuilder *) buildIntelligence:(float) value;
- (CharacterBuilder *) buildAgility:(float) value;
- (CharacterBuilder *) buildAggressiveness:(float) value;
@end
@implementation StandardCharacterBuilder
- (CharacterBuilder *) buildStrength:(float) value
{
// update the protection value of the character
_character.protection *= value;
// update the power value of the character
_character.power *= value;
// finally set the strength value and return this builder
return [super buildStrength:value];
}
- (CharacterBuilder *) buildStamina:(float) value
{
// update the protection value of the character
_character.protection *= value;
// update the power value of the character
_character.power *= value;
// finally set the strength value and return this builder
return [super buildStamina:value];
}
- (CharacterBuilder *) buildIntelligence:(float) value
{
// update the protection value of the character
_character.protection *= value;
// update the power value of the character
_character.power /= value;
// finally set the strength value and return this builder
return [super buildIntelligence:value];
}
- (CharacterBuilder *) buildAgility:(float) value
{
// update the protection value of the character
_character.protection *= value;
// update the power value of the character
_character.power /= value;
// finally set the strength value and return this builder
return [super buildAgility:value];
}
- (CharacterBuilder *) buildAggressiveness:(float) value
{
// update the protection value of the character
_character.protection /= value;
// update the power value of the character
_character.power *= value;
// finally set the strength value and return this builder
return [super buildAggressiveness:value];
}
@end
接下来,定义指导者 ChasingGame
类,其提供了创建游戏者和敌人角色的方法。
@interface ChasingGame : NSObject
{
}
- (Character *) createPlayer:(CharacterBuilder *) builder;
- (Character *) createEnemy:(CharacterBuilder *) builder;
@end
@implementation ChasingGame
- (Character *) createPlayer:(CharacterBuilder *) builder
{
// an alternative way to build a character
[[[[[[builder buildNewCharacter]
buildStrength:50.0]
buildStamina:25.0]
buildIntelligence:75.0]
buildAgility:65.0]
buildAggressiveness:35.0];
return [builder character];
}
- (Character *) createEnemy:(CharacterBuilder *) builder
{
[builder buildNewCharacter];
[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
就可以创建相应的游戏和敌人角色。
CharacterBuilder *characterBuilder = [[[StandardCharacterBuilder alloc] init] autorelease];
ChasingGame *game = [[[ChasingGame alloc] init] autorelease];
Character *player = [game createPlayer:characterBuilder];
Character *enemy = [game createEnemy:characterBuilder];
总结
建造者模式能帮助构建涉及部件与表现的各种组合的对象。没有这一模式,知道构建对象所需细节的 Director 可能最终会变成一个庞大的类,带有无数用于构建同一个类的各种表现的内嵌算法。