簡介
在軟體開發中,存在大量複雜物件,它們擁有一系列成員屬性,這些成員屬性中有些是引用型別的成員物件。而且在這些複雜物件中,還可能存在一些限制條件,如某些屬性沒有賦值則複雜物件不能作為一個完整的產品使用;有些屬性的賦值必須按照某個順序,一個屬性沒有賦值之前,另一個屬性可能無法賦值等。
由於組合部件的過程很複雜,因此,這些部件的組合過程往往被“外部化”到一個稱作建造者的物件裡,建造者返還給客戶端的是一個已經建造完畢的完整產品物件,而使用者無須關心該物件所包含的屬性以及它們的組裝方式,這就是建造者模式的模式動機。
建造者模式(Builder Pattern)使用多個簡單的物件一步一步構建成一個複雜的物件。這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。
例項
建造者模式包含如下角色:
Builder
:抽象建造者ConcreteBuilder
:具體建造者Director
:指揮者Product
:產品
電腦是每個程式設計師的標配,主要配件有:CPU、主機板、記憶體、顯示卡、電源。當前主要有兩大平臺:AMD
和 Intel
,但是兩個平臺的一些零件是不一樣的。所以肥宅在組裝兩個平臺時選擇的配件也是不一樣的。
產品(電腦):
public class Computer {
/**
* cpu
*/
private String cpu;
/**
* 主機板
*/
private String motherboar;
/**
* 記憶體
*/
private String ram;
/**
* 顯示卡
*/
private String graphicsCard;
/**
* 電源
*/
private String power;
//setter and getter
// toString
}
複製程式碼
抽象工廠:
abstract class AbstractComputerBuilder {
/**
* 選擇CPU
*/
abstract void buildCPU();
/**
* 選擇主機板
*/
abstract void buildMotherboar();
/**
* 選擇記憶體
*/
abstract void buildRam();
/**
* 選擇顯示卡
*/
abstract void buildGraphicsCard();
/**
* 選擇電源
*/
abstract void buildPower();
/**
* 獲取電腦
*/
abstract Computer getComputer();
}
複製程式碼
具體建造者:
// AMD電腦 建造者
public class AmdComputerBuilder extends AbstractComputerBuilder {
private Computer computer = new Computer();
@Override
void buildCPU() {
computer.setCpu("2700x");
}
@Override
void buildMotherboar() {
computer.setMotherboar("華碩 ROG X470");
}
@Override
void buildRam() {
computer.setRam("芝奇 DDR4 8G");
}
@Override
void buildGraphicsCard() {
computer.setGraphicsCard("vega 56");
}
@Override
void buildPower() {
computer.setPower("EVGA 750W");
}
@Override
Computer getComputer() {
return computer;
}
}
// Intel 電腦建造者
public class IntelComputerBuilder extends AbstractComputerBuilder {
private Computer computer = new Computer();
@Override
void buildCPU() {
computer.setCpu("i7 8700");
}
@Override
void buildMotherboar() {
computer.setMotherboar("微星 Z370");
}
@Override
void buildRam() {
computer.setRam("金士頓 DDR4 8G");
}
@Override
void buildGraphicsCard() {
computer.setGraphicsCard("GTX 1080Ti");
}
@Override
void buildPower() {
computer.setPower("海韻 750W");
}
@Override
Computer getComputer() {
return computer;
}
}
複製程式碼
指揮者:
public class ComputerDirector {
public void construct(AbstractComputerBuilder builder) {
builder.buildCPU();
builder.buildMotherboar();
builder.buildRam();
builder.buildGraphicsCard();
builder.buildPower();
}
}
複製程式碼
測試:
public class Fz {
@Test
public void build() {
ComputerDirector director = new ComputerDirector();
AmdComputerBuilder amdComputerBuilder = new AmdComputerBuilder();
director.construct(amdComputerBuilder);
Computer amdComputer = amdComputerBuilder.getComputer();
System.out.println("選擇AMD平臺配件:" + amdComputer);
IntelComputerBuilder intelComputerBuilder = new IntelComputerBuilder();
director.construct(intelComputerBuilder);
Computer intelComputer = intelComputerBuilder.getComputer();
System.out.println("選擇Intel平臺配件:" + intelComputer);
}
}
複製程式碼
類圖
優點
- 建造者模式的封裝性很好。使用建造者模式可以有效的封裝變化,在使用建造者模式的場景中,一般產品類和建造者類是比較穩定的,因此,將主要的業務邏輯封裝在導演類中對整體而言可以取得比較好的穩定性。
- 在建造者模式中,客戶端不必知道產品內部組成的細節,將產品本身與產品的建立過程解耦,使得相同的建立過程可以建立不同的產品物件。
- 可以更加精細地控制產品的建立過程。將複雜產品的建立步驟分解在不同的方法中,使得建立過程更加清晰,也更方便使用程式來控制建立過程。
- 建造者模式很容易進行擴充套件。如果有新的需求,通過實現一個新的建造者類就可以完成,基本上不用修改之前已經測試通過的程式碼,因此也就不會對原有功能引入風險。符合開閉原則。
缺點
- 建造者模式所建立的產品一般具有較多的共同點,其組成部分相似,如果產品之間的差異性很大,則不適合使用建造者模式,因此其使用範圍受到一定的限制。
- 如果產品的內部變化複雜,可能會導致需要定義很多具體建造者類來實現這種變化,導致系統變得很龐大。
適用場景
在以下情況下可以使用建造者模式:
- 需要生成的產品物件有複雜的內部結構,這些產品物件通常包含多個成員屬性。
- 需要生成的產品物件的屬性相互依賴,需要指定其生成順序。
- 物件的建立過程獨立於建立該物件的類。在建造者模式中引入了指揮者類,將建立過程封裝在指揮者類中,而不在建造者類中。
- 隔離複雜物件的建立和使用,並使得相同的建立過程可以建立不同的產品。
總結
建造者模式與工廠模式類似,適用的場景也很相似。建造者模式僅僅只比工廠模式多了一個”指揮者”的角色。在建造者模式的類圖中,假如把這個導演類看做是最終呼叫的客戶端,那麼圖中剩餘的部分就可以看作是一個簡單的工廠模式了。
建造者模式一般用來建立更為複雜的物件,因為物件的建立過程更為複雜,因此將物件的建立過程獨立出來組成一個新的類——導演類。也就是說,工廠模式是將物件的全部建立過程封裝在工廠類中,由工廠類向客戶端提供最終的產品;而建造者模式中,建造者類一般只提供產品類中各個元件的建造,而將具體建造過程交付給導演類。由導演類負責將各個元件按照特定的規則組建為產品,然後將組建好的產品交付給客戶端。建造者模式更加關注與零件裝配的順序。
一般來說,如果產品的建造很複雜,那麼請用工廠模式;如果產品的建造更復雜,那麼請用建造者模式。