背景
假设有一个需求:需求出产一辆轿车,轿车需求引擎、车轮、方向盘、车身等,不同品牌的轿车引擎、车轮等各不相同。现在,用户需求一辆宝马轿车,可能代码会这样写:
struct Car {
var parts = [String]()
mutating func add(part: String) {
parts.append(part)
}
}
class BWMCarBuilder {
func build() -> Car {
var car = Car()
car.add(part: "宝马引擎")
car.add(part: "宝马车轮")
car.add(part: "宝马方向盘")
car.add(part: "宝马车身")
return car
}
}
那假设用户需求购买一台奔驰轿车,那我们能够再新建一个BenchiBuilder
,来创立轿车:
class BenchiBuilder {
func build() -> Car {
var car = Car()
car.add(part: "奔驰引擎")
car.add(part: "奔驰车轮")
car.add(part: "奔驰方向盘")
car.add(part: "奔驰车身")
return car
}
}
现在,现已能够得到宝马
和奔驰
轿车,可是这儿面有个问题,可能会存在编程不注意,轿车会少添加一个部分,比方忘掉添加引擎或车身等。最好的办法就是,凡是制作轿车,都有必要要有引擎、车轮、方向盘及车身。
制作者形式
上述的问题我们能够经过制作者形式来优化。制作轿车的进程是安稳的,都需求引擎、车轮、方向盘及车身,仅仅详细的制作细节不同。但对于用户来说,只需求告诉制作商,我需求一辆宝马,制作商只需求给一辆宝马就行了,用户不关心制作车的详细进程以及细节。假设需求将一个杂乱目标的构建与它的表明别离,使得相同的构建进程能够创立不同的表明的意图时,就能够运用‘制作者形式’,又能够叫‘生成器形式’。运用了制作者形式,用户只需求指定制作的类型就能够得到想要的产品,而详细的制作进程和细节不需求知道。
制作者形式:将一个杂乱目标的构建与它的表明别离,使得相同的构建进程能够创立不同的表明。
主要人物与联系
- Builder:创立一个Product目标的各个部件指定的笼统接口
- ConcreteBuilder:详细制作者,完成了Builder接口,结构和装配各个部件
- Director:指挥制作进程
- Product:产品人物
UML
classDiagram
direction BT
class Director {
-construct()
}
class Builder {
<<interface>>
-buildEngine()
-buildWheel()
-buildSteeringWheel()
-buildBody()
}
class BWMBuilder {
-buildEngine()
-buildWheel()
-buildSteeringWheel()
-buildBody()
}
class BenchiBuilder {
-buildEngine()
-buildWheel()
-buildSteeringWheel()
-buildBody()
}
class Car
Director o--> Builder : builder
BenchiBuilder ..|> Builder
BWMBuilder ..|> Builder
BWMBuilder ..> Car
BenchiBuilder ..> Car
举例说明
还是以制作轿车为例,下面以制作者形式来改造代码。
- 产品(这儿就是轿车)
struct Car: CustomStringConvertible {
var parts = [String]()
mutating func add(part: String) {
parts.append(part)
}
var description: String {
var res = "轿车的组成部件:"
parts.forEach { part in
res += part + "、"
}
return res
}
}
- 笼统制作者(结构一个轿车有必要要有引擎、车轮、方向盘、车身)
protocol Builder {
var car: Car { set get }
func buildEngine()
func buildWheel()
func buildSteeringWheel()
func buildBody()
}
- 详细制作者(宝马制作者和奔驰制作者,都完成了
Builder
的接口)
class BWMBuilder: Builder {
var car: Car = Car()
func buildEngine() {
car.add(part: "宝马引擎")
}
func buildWheel() {
car.add(part: "宝马车轮")
}
func buildSteeringWheel() {
car.add(part: "宝马方向盘")
}
func buildBody() {
car.add(part: "宝马车身")
}
}
class BenchiBuilder: Builder {
var car: Car = Car()
func buildEngine() {
car.add(part: "奔驰引擎")
}
func buildWheel() {
car.add(part: "奔驰车轮")
}
func buildSteeringWheel() {
car.add(part: "奔驰方向盘")
}
func buildBody() {
car.add(part: "奔驰车身")
}
}
- 指挥者(Director)
class Director {
func construct(builder: Builder) {
builder.buildEngine()
builder.buildWheel()
builder.buildSteeringWheel()
builder.buildBody()
}
}
假设没有Director
这一层,那么外部调用就有必要要知道Builder
有哪些办法。Director
作用:操控制作进程,用来阻隔用户与制作进程的相关
- 客户端调用
func testBuilderClient() {
let director = Director()
let bwmBuilder = BWMBuilder()
director.construct(builder: bwmBuilder)
let bwmCar = bwmBuilder.car
print(bwmCar) // 轿车的组成部件:宝马引擎、宝马车轮、宝马方向盘、宝马车身、
let benchiBuilder = BenchiBuilder()
director.construct(builder: benchiBuilder)
let benchiCar = benchiBuilder.car
print(benchiCar) // 轿车的组成部件:奔驰引擎、奔驰车轮、奔驰方向盘、奔驰车身、
}
- 客户端调用(不运用
Director
)
func testBuilderClient() {
let bmwBuilder = BWMBuilder()
bmwBuilder.buildEngine()
bmwBuilder.buildWheel()
bmwBuilder.buildSteeringWheel()
bmwBuilder.buildBody()
let bwmCar = bmwBuilder.car
print(bwmCar)
let benchiBuilder = BenchiBuilder()
benchiBuilder.buildEngine()
benchiBuilder.buildWheel()
benchiBuilder.buildSteeringWheel()
benchiBuilder.buildBody()
let benchiCar = benchiBuilder.car
print(benchiCar)
}
总结
优点:
- 制作者形式,使得制作代码与表明代码别离,因为隐藏了该产品是怎么组装的,所以假设需求改变一个产品的内部表明,只需求再定义一个详细的制作者就能够了。
- 将杂乱产品的创立进程分解在不同的办法中,使得创立进程更加清晰,也更便利运用程序来操控创立进程。
- 添加新的制作者无需修改原有类的代码,指挥者针对笼统制作者编程,扩展便利,复合‘开闭准则’。
缺陷
- 制作者形式创立的产品一般都是具有较多的共同点,组成部分都很相似,假设产品的组成部分差距过多,则不适合运用制作者。
- 假设产品相当杂乱,比方组成部分有许多,则
Builder
类中就需求抽取更多的代码,以及可能会发生许多详细的Buidler类,使得类文件较多。