类型 配置
主体 Intel 天逸510S
内存 DDR4
视频接口 VGA/HDMI
CPU 4核i3
显卡 集成
硬盘 西部数据7200rpm
输入设备 罗技鼠标+硬盘
显示器 三星xx型号

铜锣: 感觉不错嘛,回头拿过来跑跑分。

风海: 其实有一些参数我还没放上来呢,我在想,如果有一天我是负责写代码处理这一块的录入,那我建一个 Computer 类岂不是构造函数要包含这么一大坨数据。

铜锣: 啊哈,你这个类真包含这么大坨数据的话,它就是典型的 复杂构建 问题了。

风海: 哦?那么对于复杂对象的构建,有什么好的解决方案吗?

铜锣: 设计模式倒是有这么一个模式是专门解决这个问题的,叫建造者模式,或者叫生成器模式,还有一些别的译名,不过英文名倒是统一的,叫 Builder Pattern

风海: 说到创建对象,我们之前也聊过工厂模式,这个建造者模式也负责创建对象,两者有什么区别吗?

铜锣: 当然有区别,工厂模式解决的是类型多样性的问题,建造者模式解决的是类型内部结构复杂性的问题。

风海: 这样,那你以代码为例,如果把我这台电脑写作一个类 Computer ,根据客户提供的信息进行个性化配置,那么这个类应该怎么写。

铜锣: 我先从基础写起,比如这样:

swift
class Computer {
    var body: String = ""
    var memory: String = ""
    var description: String {
        "body = (body) memory = (memory)"

风海: 看到了,你写了一个Computer类,提供了两个属性,然后呢,没看到有Builder啊。

风海: 别急,这只是起步,我往下写。

swift
class Computer {
    var body: String = ""
    var memory: String = ""
    var description: String {
        "body = (body) memory = (memory)"
    static func builder() -> Builder {
        return Builder()
    class Builder {
        let computer = Computer()
        @discardableResult
        func set(body: String) -> Builder {
            computer.body = body
            return self
        @discardableResult
        func set(memory: String) -> Builder {
            computer.memory = memory
            return self
        func build() -> Computer {
            return computer

现在,我们定义了一个Computer类,这个类的创建并不由自己完成,而是由Computer内部的一个Builder类完成,有意思吧?

风海: 理解了,所以说建造者模式要求复杂的类内部要有个Builder吗?

铜锣: 哦不不,Builder具体放在那里不是设计模式规定的,设计模式只是规划了个总体思想,具体实现是由开发者根据实际情况定夺的。

在这个例子里,在我们在创建Computer对象的时候,可以这么写

swift
let builder = Computer.builder()
builder.set(body: "Intel 天逸510S")
builder.set(memory: "DDR4")
let computer = builder.build()
print("(computer.description)")

风海: 原来如此,这时候Computer的创建被延后了,交给Builder去逐步构建属性,等构建成型后再直接创建Computer,这么写倒不错,但是代码行数还挺多的。

铜锣: 是的,所以你有没有看到,Builderset代码都会返回Builder呢,就是为了便捷性,事实上Computer的创建还可以这么写。

swift
let computer = Computer.builder()
    .set(body: "Intel 天逸510S")
    .set(memory: "DDR4")
    .build()
print("(computer.description)")

风海: 原来如此,这样确实便捷了很多。所以那个@discardableResult也是为了单纯属性设置而不打算接收返回值时不会收到编译器警告而设定的。

铜锣: 对,没错。我们还可以进一步扩展,比方说我们通过Builder来构建Computer,那么当Builder不断增加时,我们也可以做一些Builder模板,比如如下代码:

swift
class HPComputerBuilder: Computer.Builder {
    override init() {
        super.init()
        set(body: "HP 超级芯片").set(memory: "DDR4")

风海: 明白了,这样一来通过单独定义的Builder类,我们可以非常便捷的直接构建定制的Computer

铜锣: 是的。当需要使用时我们这么写:

swift
let hpComputer = HPComputerBuilder().build()
print("(hpComputer.description)")

风海: 嗯,我们聊了这么多,好像连建造者模式的定义都没给呢。

铜锣: 是啊,定义留给最后嘛。

生成器模式(英:Builder Pattern)是一种设计模式,又名:建造模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。

风海: 好了,三点几了,饮茶去了。

铜锣: 欧耶。

  • 私信