1. 程式人生 > >設計模式-05建造者模式(Builder Pattern)

設計模式-05建造者模式(Builder Pattern)

1.模式動機

比如我們要組裝一臺電腦,都知道電腦是由 CPU、主機板、記憶體、硬碟、顯示卡、機箱、顯示器、鍵盤和滑鼠組成,其中非常重要的一點就是這些硬體都是可以靈活選擇,但是組裝步驟都是大同小異(可以組一個高配置的,也可以組一個低配置的),這時建造者模式可以很好的描述這類產品的建立。

2.模式定義

建造者模式的定義:指將一個複雜物件的構造與它的表示分離,使同樣的構建過程可以建立不同的表示,這樣的設計模式被稱為建造者模式。
它是將一個複雜的物件分解為多個簡單的物件,然後一步一步構建而成。它將變與不變相分離,即產品的組成部分是不變的,但每一部分是可以靈活選擇的。

注意
建造者模式和工廠模式的關注點不同:建造者模式注重零部件的組裝過程,而工廠方法模式更注重零部件的建立過程,但兩者可以結合使用。

3.模式結構

建造者模式由產品、抽象建造者、具體建造者、指揮者等 4 個要素構成,現在我們來分析其基本結構和實現方法。

建造者模式的主要角色如下:

  • 產品角色:它是包含多個組成部件的複雜物件,由具體建造者來建立其各個部件。
  • 抽象建造者:它是一個包含建立產品各個子部件的抽象方法的介面,通常還包含一個返回複雜產品的方法getResult()
  • 具體建造者:實現抽象建造者介面,完成複雜產品的各個部件的具體建立方法。
  • 指揮者:它呼叫建造者物件中的部件構造與裝配方法完成複雜物件的建立,在指揮者中不涉及具體產品的資訊。

4.模式程式碼

# 產品角色
@Getter
@Setter
@ToString
public class Computer {
    private String cpu;
    private String ram;
    private String ssd;
}

# 抽象建造者
public abstract class AbstractComputerBuilder {
    protected Computer computer = new Computer();
    public abstract void buildCPU();
    public abstract void buildRAM();
    public abstract void buildSSD();
    public Computer getResult() {
        return computer;
    }
}

# 具體建造者
public class HighProfileComputerBuilder extends AbstractComputerBuilder {
    @Override
    public void buildCPU() {
        computer.setCpu("i9");
    }

    @Override
    public void buildRAM() {
        computer.setRam("32G");
    }

    @Override
    public void buildSSD() {
        computer.setSsd("1T");
    }
}

# 指揮者
public class Director {

    private AbstractComputerBuilder builder;

    public Director(AbstractComputerBuilder builder) {
        this.builder = builder;
    }

    public Computer construct() {
        builder.buildCPU();
        builder.buildRAM();
        builder.buildSSD();
        return builder.getResult();
    }

}

# 客戶端呼叫
public class Client {
    public static void main(String[] args) {
        AbstractComputerBuilder builder = new HighProfileComputerBuilder();
        Director director = new Director(builder);
        Computer highProfileComputer = director.construct();
        System.out.println(highProfileComputer); // Computer(cpu=i9, ram=32G, ssd=1T)
    }
}

我們也可以建造一個LowProfileComputerBuilder,客戶端呼叫時建立低配置電腦建造者即可。

程式碼分析:

  • 抽象建造者類中定義了產品的建立方法和返回方法
  • 建造者模式的結構中還引入了一個指揮者類Director,該類的作用主要有兩個:一方面它隔離了客戶與生產過程;另一方面它負責控制產品的生成過程。指揮者針對抽象建造者程式設計,客戶端只需要知道具體建造者的型別,即可通過指揮者類呼叫建造者的相關方法,返回一個完整的產品物件
  • 在客戶端程式碼中,無須關心產品物件的具體組裝過程,只需確定具體建造者的型別即可,建造者模式將複雜物件的構建與物件的表現分離開來,這樣使得同樣的構建過程可以創建出不同的表現。

5.總結

優點

  • 在建造者模式中,客戶端不必知道產品內部組成的細節,將產品本身與產品的建立過程解耦,使得相同的建立過程可以建立不同的產品物件。
  • 每一個具體建造者都相對獨立,而與其他的具體建造者無關,因此可以很方便地替換具體建造者或增加新的具體建造者,使用者使用不同的具體建造者即可得到不同的產品物件。
  • 可以更加精細地控制產品的建立過程。將複雜產品的建立步驟分解在不同的方法中,使得建立過程更加清晰,也更方便使用程式來控制建立過程。
  • 增加新的具體建造者無須修改原有類庫的程式碼,指揮者類針對抽象建造者類程式設計,系統擴充套件方便,符合“開閉原則”。

缺點

  • 建造者模式所建立的產品一般具有較多的共同點,其組成部分相似,如果產品之間的差異性很大,則不適合使用建造者模式,因此其使用範圍受到一定的限制。
  • 如果產品的內部變化複雜,可能會導致需要定義很多具體建造者類來實現這種變化,導致系統變得很龐大。

6.擴充套件:模式的簡化

我們可以使用 lombok 提供的 @Builder 註解實現簡單的建造者模式:

import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
@Builder
public class TV {
    private String name;
    private String address;
    private Date createData;
}

編譯後的程式碼如下:

import java.util.Date;

public class TV {
    private String name;
    private String address;
    private Date createData;

    TV(String name, String address, Date createData) {
        this.name = name;
        this.address = address;
        this.createData = createData;
    }

    public static TV.TVBuilder builder() {
        return new TV.TVBuilder();
    }

    public String getName() {
        return this.name;
    }

    public String getAddress() {
        return this.address;
    }

    public Date getCreateData() {
        return this.createData;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public void setCreateData(Date createData) {
        this.createData = createData;
    }

    public String toString() {
        return "TV(name=" + this.getName() + ", address=" + this.getAddress() + ", createData=" + this.getCreateData() + ")";
    }

    public static class TVBuilder {
        private String name;
        private String address;
        private Date createData;

        TVBuilder() {
        }

        public TV.TVBuilder name(String name) {
            this.name = name;
            return this;
        }

        public TV.TVBuilder address(String address) {
            this.address = address;
            return this;
        }

        public TV.TVBuilder createData(Date createData) {
            this.createData = createData;
            return this;
        }

        public TV build() {
            return new TV(this.name, this.address, this.createData);
        }

        public String toString() {
            return "TV.TVBuilder(name=" + this.name + ", address=" + this.address + ", createData=" + this.createData + ")";
        }
    }
}

呼叫者程式碼:

public class TVClient {
    public static void main(String[] args) {
        TV tv = TV.builder()
                .name("長虹")
                .address("中國")
                .createData(new Date())
                .build();
        System.out.println(tv); // TV(name=長虹, address=中國, createData=Tue Feb 11 11:58:41 CST 2020)
    }
}

正文中是標準的建造者模式,擴充套件中是簡單的建造者模式,按需選擇