建造者模式(生成器模式)的浅出理解

如何让自己的文章变的高逼格?
就是随便写一写生活里的琐事
然后加上一句 : 爱情也是如此
那文章将化腐朽为神奇
比如 :
今早我明明设置了七点的闹钟, 可是一觉醒来已经是八点, 爱情也是如此....
我中午吃了一个包子, 我说要香菇馅, 阿姨却给我猪肉馅, 爱情也是如此...
设计模式学起来好枯燥, 可是还是让人贱嗖嗖的想学, 爱情也是如此....


对于建造者模式
看过书, 也看过博客
我对这个设计模式的总结为如下几句话 :
客户(Client)想要货
于是客户告诉了指导者(Director)我想要货
于是指导者指导建造者(Builder)去建造
客户不管指导者在哪里怎么搞到的货, 总之你要给我货
就像我去买包子
我告诉大妈我要买包子
大妈给我包子
我并不去问大妈怎么做的包子
流程大概就是这个样子 : Client - Director - Builder
UML图大概是这个样子 :


UML 图

Builder是一个抽象接口, 声明了 buildPart 方法
buildPart 方法由 ConcreteBuilder 实现以构建产品 product
ConcreteBuilder 还有一个方法 getResult 方法, 用来返回产品实例
Director 定义了一个 create 方法
用来命令 Builder 的实例去创建产品
Director 和 Builder 形成一种聚合关系
Builder 是 Director 的组成部分
他们结合使整个模式运转

好了开始上代码
代码逻辑模仿我之前玩过的一款烧钱网游
省吃省喝就为买装备的烧钱网游
在网游中需要有很多角色
角色包括很多类型
有输出, 辅助, 封系
但是每种类型的角色都有共同的属性
有伤害, 防御, 速度和气血
只不过对于输出来说伤害高但是防御低
对于辅助来说伤害低但是防御高
当然你要是充钱多的话
什么都能高.....
然后角色类是这个样子 :

// HXCharacter.h
#import <UIKit/UIKit.h>

@interface HXCharacter : NSObject

/** 伤害值 */
@property (nonatomic, assign) CGFloat power;
/** 防御值 */
@property (nonatomic, assign) CGFloat protection;
/** 速度值 */
@property (nonatomic, assign) CGFloat velocity;
/** 气血值 */
@property (nonatomic, assign) CGFloat blood;
/** 角色类型 */
@property (nonatomic, copy) NSString *type;

//查看角色属性
- (void)lookLook;
@end

// HXCharacter.m
#import "HXCharacter.h"

@implementation HXCharacter

- (instancetype)init {
    if (self = [super init]) {
        //搞一搞初始值
        self.power = 1.0;
        self.protection = 1.0;
        self.velocity = 1.0;
        self.blood = 1.0;
    }
    return self;
}

- (void)lookLook {
    NSLog(@"\n  我是啥 : %@,   \n我的伤害 : %.2f,   \n我的防御 : %.2f,   \n我的速度 : %.2f,   \n我的气血 : %.2f,",self.type, self.power,self.protection,self.velocity,self.blood);
}

@end

他拥有很多属性和一个看一看方法(lookLook)
看一看方法可以输出这个角色的属性

然后来创建抽象 Builder 类:

// HXCharacterBuilder.h
#import <Foundation/Foundation.h>
#import "HXCharacter.h"

@interface HXCharacterBuilder : NSObject

@property (nonatomic, strong) HXCharacter *character;

/** 获取创建好的角色 */
- (HXCharacter *)getCharacter;

/** 增加伤害 */
- (instancetype)increasePower:(NSInteger)power;

/** 增加防御 */
- (instancetype)increaseProtection:(NSInteger)protection;

/** 增加速度 */
- (instancetype)increaseVelocity:(NSInteger)velocity;

/** 增加气血 */
- (instancetype)increaseBlood:(NSInteger)blood;

@end

// HXCharacterBuilder.m
#import "HXCharacterBuilder.h"

@implementation HXCharacterBuilder

- (instancetype)init {
    if (self = [super init]) {
        [self createCharacter];
    }
    return self;
}

- (void)createCharacter {
    self.character  = [[HXCharacter alloc] init];
}

/** 获取创建好的角色 */
- (HXCharacter *)getCharacter {
    return self.character;
}

/** 增加伤害 */
- (instancetype)increasePower:(NSInteger)power {
    self.character.power = power;
    return self;
}

/** 增加防御 */
- (instancetype)increaseProtection:(NSInteger)protection {
    self.character.protection = protection;
    return self;
}

/** 增加速度 */
- (instancetype)increaseVelocity:(NSInteger)velocity {
    self.character.velocity = velocity;
    return self;
}

/** 增加气血 */
- (instancetype)increaseBlood:(NSInteger)blood {
    self.character.blood = blood;
    return self;
}

@end

他实现了对角色属性的默认操作
还有一个 getCharacter 方法来返回创建好的角色

然后是继承 Builder 的 HXWarriorCharacterBuilder 类
HXWarriorCharacterBuilder 用来创建输出角色的建造者类

#import "HXCharacterBuilder.h"

@interface HXWarriorCharacterBuilder : HXCharacterBuilder

@end
#import "HXWarriorCharacterBuilder.h"

@implementation HXWarriorCharacterBuilder

/** 增加伤害 */
- (instancetype)increasePower:(NSInteger)power {
    self.character.power = power * 10;
    return self;
}

/** 增加防御 */
- (instancetype)increaseProtection:(NSInteger)protection {
    self.character.protection = protection * 5;
    return self;
}

/** 增加速度 */
- (instancetype)increaseVelocity:(NSInteger)velocity {
    self.character.velocity = velocity * 5;
    return self;
}

/** 增加气血 */
- (instancetype)increaseBlood:(NSInteger)blood {
    self.character.blood = blood * 5;
    return self;
}

- (void)createCharacter {
    self.character = [[HXCharacter alloc] init];
    self.character.type = @"我是战士, 我是一名输出";
}

@end

这个类实现了针对于输出角色属性的操作
创建角色过程中, 调用方法不同, 是对角色不同属性的创建
根据属性类型的不同, 属性值将乘以不同的成长比例
对于输出角色伤害的成长比例高, 而防御气血的成长比例稍微低一些
在实际应用这个模式的时候, 这里可能会有更复杂的对产品组件的创建代码

顺便搞一个用来创建辅助角色的建造者类

// HXDoctorCharacterBuilder.h
#import "HXCharacterBuilder.h"

@interface HXDoctorCharacterBuilder : HXCharacterBuilder

@end

// HXDoctorCharacterBuilder.m
#import "HXDoctorCharacterBuilder.h"

@implementation HXDoctorCharacterBuilder

/** 增加伤害 */
- (instancetype)increasePower:(NSInteger)power {
    self.character.power = power * 2;
    return self;
}

/** 增加防御 */
- (instancetype)increaseProtection:(NSInteger)protection {
    self.character.protection = protection * 10;
    return self;
}

/** 增加速度 */
- (instancetype)increaseVelocity:(NSInteger)velocity {
    self.character.velocity = velocity * 8;
    return self;
}

/** 增加气血 */
- (instancetype)increaseBlood:(NSInteger)blood {
    self.character.blood = blood * 10;
    return self;
}

- (void)createCharacter {
    self.character = [[HXCharacter alloc] init];
    self.character.type = @"我是医生, 我是一名辅助";
}

@end

同理于输出角色建造者类
对于辅助角色伤害的成长比例低, 而防御气血的成长比例稍微高一些

然后是指导者 Director 的类

// HXGameDirector.h
#import <Foundation/Foundation.h>
#import "HXCharacterBuilder.h"
#import "HXCharacter.h"

@interface HXGameDirector : NSObject
- (instancetype)initWithBuilder:(HXCharacterBuilder *)builder;

/** 创建辅助角色 */
- (void)createAuxiliaryCharacter;

/** 创建输出角色 */
- (void)createExportCharacter;
@end

// HXGameDirector.m
#import "HXGameDirector.h"

@interface HXGameDirector()
@property (nonatomic, strong) HXCharacterBuilder *builder;
@end

@implementation HXGameDirector
- (instancetype)initWithBuilder:(HXCharacterBuilder *)builder {
    if (self = [super init]) {
        self.builder = builder;
    }
    return self;
}

/** 创建辅助角色 */
- (void)createAuxiliaryCharacter {
    [self.builder increasePower:20];
    [self.builder increaseProtection:100];
    [self.builder increaseVelocity:80];
    [self.builder increaseBlood:100];
}

/** 创建输出角色 */
- (void)createExportCharacter {
     // 因为创建属性的方法, 返回了 builder 所以也可以这么调用
    [[[[self.builder increasePower:100]increaseProtection:50]increaseVelocity:100]increaseBlood:50];
}

@end

指导者有两个方法
分别是根据不同属性值创建输出角色和辅助角色
客户端将这么使用 :

- (void)viewDidLoad {
    [super viewDidLoad];

    //创建生成器
    HXCharacterBuilder *warriorBuilder = [[HXWarriorCharacterBuilder alloc] init];
    //根据生成器创建指导者
    HXGameDirector *warriorDirector = [[HXGameDirector alloc] initWithBuilder:warriorBuilder];
    //指导者利用生成器去生产
    [warriorDirector createExportCharacter];
    //在生成器中获取角色
    HXCharacter *warriorCharacter = [warriorBuilder getCharacter];
    //看看角色什么样
    [warriorCharacter lookLook];
    
    HXCharacterBuilder *doctorBuilder = [[HXDoctorCharacterBuilder alloc] init];
    HXGameDirector *doctorDirector = [[HXGameDirector alloc] initWithBuilder:doctorBuilder];
    [doctorDirector createAuxiliaryCharacter];
    HXCharacter *doctorCharacter = [doctorBuilder getCharacter];
    [doctorCharacter lookLook];
}

打印结果 :

HXBuilderPattern[17708:3030502] 
我是啥 : 我是战士, 我是一名输出,   
我的伤害 : 1000.00,   
我的防御 : 250.00,   
我的速度 : 500.00,   
我的气血 : 250.00,
HXBuilderPattern[17708:3030502] 
我是啥 : 我是医生, 我是一名辅助,   
我的伤害 : 40.00,   
我的防御 : 1000.00,   
我的速度 : 640.00,   
我的气血 : 1000.00,

到这里使用建造者模式把角色创建结束了
有一点需要说明 :
就是为什么要从 builder 中去获取最终产品
如果用 dirctor 直接返回产品的话, 客户就不需要知道 builder 了
这岂不是很方便?
但是这样的话, dirctor 就变成了工厂
dirctor 的 create 方法就变成了生产抽象产品的工厂方法
工厂设计模式看这里
而且 dirctor 将与所支持的产品绑定在一起
降低了模式的可复用性
对这里的理解, 我感觉还不是很到位, 希望有大神指点

最后区别一下建造者模式与抽象工厂的特点 :

建造者模式 :
构建复杂对象
以多个步骤构建对象
以多种方式构建对象
多步构建, 最后一步返回产品
专注一个特定产品的创建

抽象工厂 :
构建简单对象也可构建复杂对象
以单一步骤构建对象
以单一方式构建对象
立刻返回构建产品
强调一套产品
这里是代码

感谢阅读
你的支持是我写作的唯一动力


享元模式
工厂模式
中介者模式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容