背景

假设有一个需求:需求出产一辆轿车,轿车需求引擎、车轮、方向盘、车身等,不同品牌的轿车引擎、车轮等各不相同。现在,用户需求一辆宝马轿车,可能代码会这样写:

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

举例说明

还是以制作轿车为例,下面以制作者形式来改造代码。

  1. 产品(这儿就是轿车)
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
  }
}
  1. 笼统制作者(结构一个轿车有必要要有引擎、车轮、方向盘、车身)
protocol Builder {
  var car: Car { set get }
  func buildEngine()
  func buildWheel()
  func buildSteeringWheel()
  func buildBody()
}
  1. 详细制作者(宝马制作者和奔驰制作者,都完成了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: "奔驰车身")
  }
}
  1. 指挥者(Director)
class Director {
  func construct(builder: Builder) {
    builder.buildEngine()
    builder.buildWheel()
    builder.buildSteeringWheel()
    builder.buildBody()
  }
}

假设没有Director这一层,那么外部调用就有必要要知道Builder有哪些办法。Director作用:操控制作进程,用来阻隔用户与制作进程的相关

  1. 客户端调用
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) // 轿车的组成部件:奔驰引擎、奔驰车轮、奔驰方向盘、奔驰车身、
}
  1. 客户端调用(不运用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)
}

总结

优点:

  1. 制作者形式,使得制作代码与表明代码别离,因为隐藏了该产品是怎么组装的,所以假设需求改变一个产品的内部表明,只需求再定义一个详细的制作者就能够了。
  2. 将杂乱产品的创立进程分解在不同的办法中,使得创立进程更加清晰,也更便利运用程序来操控创立进程。
  3. 添加新的制作者无需修改原有类的代码,指挥者针对笼统制作者编程,扩展便利,复合‘开闭准则’。

缺陷

  1. 制作者形式创立的产品一般都是具有较多的共同点,组成部分都很相似,假设产品的组成部分差距过多,则不适合运用制作者。
  2. 假设产品相当杂乱,比方组成部分有许多,则Builder类中就需求抽取更多的代码,以及可能会发生许多详细的Buidler类,使得类文件较多。