1. 什么是建造者模式
建造者模式(Builder Pattern) 定义
Separate the construction of a complex object from its representation so that the same constructionprocess can create different representations
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。建造者模式属于对象创建型模式。根据中文翻译的不同,建造者模式又可以称为生成器模式。
2. 角色组成
- Product: 最终要生成的对象。
- Builder:构建者的抽象基类(有时会使用接口代替)。其定义了构建Product的抽象步骤,其实体类需要实现这些步骤。其会包含一个用来返回最终产品的方法。
- ConcreteBuilder: Builder的实现类。
-
Director: 主管类,决定如何构建最终产品的算法。
3. 代码实现
假设你想买车,心里有个预售大概20万左右的B级车(Car),这个时候你就会到网上(CarDirector)搜索符合预算的车型,搜索到比较心仪的两款车分别为别克的君威和丰田的凯美瑞。但是在裸车的基础上,买车还有很多可选配置,比如天窗,一键启动等,这些都是需要额外加钱的,这些配置项基本都是共通的,我们可以定义一个抽象模拟生成器(CarBuilder)。为了更好的比对两款车加上不同配置后的价格,不同款的车肯定需要有不同的具体生成器君威为(BuickCarBuilder), 凯美瑞为(ToyotaCarBuilder)
代码实现如下:
- 定义产品类Car
// Car.h
#import
@interface Car : NSObject
@property (nonatomic, copy) NSString *baseCar;//裸车(必选)
@property (nonatomic, assign) CGFloat price;//价格(必选)
@property (nonatomic, copy) NSString *brandName;//品牌(必选)
@property (nonatomic, copy) NSString *skylight;//天窗(可选)
@property (nonatomic, copy) NSString *autoStart;//一键启动(可选)
- (instancetype)initWithBaseCar:(NSString *)baseCar price:(CGFloat)price;
@end
// Car.m
#import "Car.h"
@implementation Car
- (instancetype)initWithBaseCar:(NSString *)baseCar price:(CGFloat)price {
self = [super init];
if (self) {
_baseCar = baseCar;
_price = price;
}
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:@"brandName = %@,baseCar = %@, skylight = %@, autoStart = %@, price = %lf", self.brandName, self.baseCar, self.skylight, self.autoStart, self.price];
}
@end
- 定义抽象建造者类CarBuilder,具体建造者类BuickCarBuilder和ToyotaCarBuilder
// CarBuilder.h
#import
#import "Car.h"
@interface CarBuilder : NSObject
@property (nonatomic, strong) Car *car;
- (instancetype)initWithBaseCar:(NSString *)baseCar price:(CGFloat)price;
- (void)setBrandName;
- (void)addSkylight;
- (void)addAutoStart;
- (Car *)getNewCar;
@end
// CarBuilder.m
#import "CarBuilder.h"
@implementation CarBuilder
- (instancetype)initWithBaseCar:(NSString *)baseCar price:(CGFloat)price {
self = [super init];
if (self) {
_car = [[Car alloc] initWithBaseCar:baseCar price:price];
}
return self;
}
- (void)setBrandName {
NSAssert(false, @"must implement in subClass");
}
- (void)addSkylight {
NSAssert(false, @"must implement in subClass");
}
- (void)addAutoStart {
NSAssert(false, @"must implement in subClass");
}
- (Car *)getNewCar {
return _car;
}
@end
// BuickCarBuiler.h
#import "CarBuilder.h"
@interface BuickCarBuiler : CarBuilder
@end
// BuickCarBuiler.m
#import "BuickCarBuiler.h"
@implementation BuickCarBuiler
- (void)setBrandName {
self.car.brandName = @"别克";
}
- (void)addSkylight {
self.car.skylight = @"别克天窗";
self.car.price += 10000;
}
- (void)addAutoStart {
self.car.autoStart = @"别克一键启动";
self.car.price += 12000;
}
@end
// ToyotaCarBuilder.h
#import "CarBuilder.h"
@interface ToyotaCarBuilder : CarBuilder
@end
// ToyotaCarBuilder.m
#import "ToyotaCarBuilder.h"
@implementation ToyotaCarBuilder
- (void)setBrandName {
self.car.brandName = @"丰田";
}
- (void)addSkylight {
self.car.skylight = @"丰田天窗";
self.car.price += 9500;
}
- (void)addAutoStart {
self.car.autoStart = @"丰田一键启动";
self.car.price += 13000;
}
@end
- 定义主管类CarDirector
// CarDirector.h
#import
#import "CarBuilder.h"
@interface CarDirector : NSObject
- (instancetype)initWithCarBuilder:(CarBuilder *)carBuilder;
- (void)makeCar;
@end
// CarDirector.m
#import "CarDirector.h"
@interface CarDirector()
@property (nonatomic, strong) CarBuilder *carBuilder;
@end
@implementation CarDirector
- (instancetype)initWithCarBuilder:(CarBuilder *)carBuilder {
self = [super init];
if (self) {
_carBuilder = carBuilder;
}
return self;
}
- (void)makeCar {
[_carBuilder setBrandName];
[_carBuilder addAutoStart];
[_carBuilder addSkylight];
}
@end
- 调用测试,调用过程为 创建具体建造器--通过建造起初始化主管实例--使用主管实例对产品进行构建--生成产品实例
+ (void)test {
BuickCarBuiler *buickBuilder = [[BuickCarBuiler alloc] initWithBaseCar:@"君威" price:190000];
CarDirector *buickDirector = [[CarDirector alloc] initWithCarBuilder:buickBuilder];
[buickDirector makeCar];
Car *buickCar = [buickBuilder getNewCar];
NSLog(@"%@", buickCar);
ToyotaCarBuilder *toyotaBuilder = [[ToyotaCarBuilder alloc] initWithBaseCar:@"凯美瑞" price:200000];
CarDirector *toyotaDirector = [[CarDirector alloc] initWithCarBuilder:toyotaBuilder];
[toyotaDirector makeCar];
Car *toyotaCar = [toyotaBuilder getNewCar];
NSLog(@"%@", toyotaCar);
}
-
执行结果
4. 分析
- 符合依赖倒置原则,建造者之间相互独立,有利于后续的拓展
- 将创建过程进行模块化,可以进行自由组合得到自定义产品
- 封装性好,屏蔽了产品内部组成部分,便于控制细节变化风险
- 但是如果产品内部变化复杂,将会生成很多建造者类
- 产品的组成部分必须相同,这限制了其使用范围。
5. 适用范围
- 创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化
- 创建过程中,相同的创建部件方法,不同的执行顺序产生不同的结果
6. 和工厂方法异同
- 两者都是创建型设计模式,都能对创建过程进行有效的封装,做到使用和创建分离
- 建造者模式中强调的是零件的组装,组装顺序不同对象效能也不同,这才是建造者模式要表达的核心意义
- 建造者模式最主要的功能是基本方法的调用顺序安排,也就是这些基本方法已经实现了,通俗地说就是零件的装配,顺序不同产生的对象也不同;而工厂方法则重点是创建,创建零件是它的主要职责,组装顺序则不是它关心的。
7. 模式拓展
应用过程中可以根据需要改变,如果创建的产品种类只有一种,只需要一个具体建造者,这时可以省略掉抽象建造者,甚至可以省略掉指挥者角色。
代码示例:
假设我们到KFC吃东西,可选食物有汉堡、可乐、薯条、牛奶等,我们可以通过自助下单机(KFCOrderBuilder)进行自选下单,生成想要的订单(KFCOrder)
代码如下:
- 订单类(KFCOrder)
// KFCOrder.h
#import
@interface KFCOrder : NSObject
@property (nonatomic, strong) NSString *hamburger;
@property (nonatomic, strong) NSString *frenchFries;
@property (nonatomic, strong) NSString *coke;
@property (nonatomic, strong) NSString *milk;
@property (nonatomic, strong) NSString *friedChi;
@end
// KFCOrder.m
#import "KFCOrder.h"
@implementation KFCOrder
- (NSString *)description {
return [NSString stringWithFormat:@"订单:%@,%@,%@,%@,%@", self.hamburger, self.frenchFries, self.coke, self.friedChi, self.milk];
}
@end
- 订单建造器(KFCOrderBuilder),为了更加利于灵活配置,这里采用了链式写法
// KFCOrderBuilder.h
#import
#import "KFCOrder.h"
@class KFCOrderBuilder;
typedef KFCOrderBuilder *(^orderBuildBlock)(NSString *type, NSInteger count);
@interface KFCOrderBuilder : NSObject
- (KFCOrder *)getKFCOrder;
- (orderBuildBlock)hamburger;
- (orderBuildBlock)frenchFries;
- (orderBuildBlock)friedChi;
- (orderBuildBlock)milk;
- (orderBuildBlock)coke;
@end
// KFCOrderBuilder.m
#import "KFCOrderBuilder.h"
@interface KFCOrderBuilder()
@property (nonatomic, strong) KFCOrder *order;
@end
@implementation KFCOrderBuilder
- (instancetype)init{
self = [super init];
if (self) {
_order = [[KFCOrder alloc] init];
}
return self;
}
- (KFCOrder *)getKFCOrder {
return _order;
}
- (orderBuildBlock)hamburger {
return ^KFCOrderBuilder* (NSString *hamburger, NSInteger count) {
self.order.hamburger = [NSString stringWithFormat:@"%@ x%ld", hamburger, count];
return self;
};
}
- (orderBuildBlock)frenchFries {
return ^KFCOrderBuilder* (NSString *frenchFries, NSInteger count) {
self.order.frenchFries = [NSString stringWithFormat:@"%@ x%ld", frenchFries, count];;
return self;
};
}
- (orderBuildBlock)coke {
return ^KFCOrderBuilder* (NSString *coke, NSInteger count) {
self.order.coke = [NSString stringWithFormat:@"%@ x%ld", coke, count];;
return self;
};
}
- (orderBuildBlock)milk {
return ^KFCOrderBuilder* (NSString *milk, NSInteger count) {
self.order.milk = [NSString stringWithFormat:@"%@ x%ld", milk, count];;
return self;
};
}
- (orderBuildBlock)friedChi {
return ^KFCOrderBuilder* (NSString *friedChi, NSInteger count) {
self.order.friedChi = [NSString stringWithFormat:@"%@ x%ld", friedChi, count];;
return self;
};
}
@end
- 进行调用,可以看到采取链式的方式生成想要的订单
+ (void)test1 {
KFCOrder *order = [[KFCOrderBuilder alloc] init].hamburger(@"鸡腿堡",2)
.frenchFries(@"中份薯条",2)
.coke(@"中可",2)
.milk(@"鲜奶",1)
.friedChi(@"炸芝士",2)
.getKFCOrder;
NSLog(@"%@", order);
}
-
运行结果
当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。