一、什么是建造者模式
建造者模式是將一個(gè)復(fù)雜的對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
建造者模式屬于創(chuàng)建型模式,對(duì)使用者而言,只需要指定需要建造的類型就可以獲得對(duì)象,建造過程和細(xì)節(jié)不需要了解。在實(shí)際的開發(fā)過程中,使用 Builder Pattern 來替代多參數(shù)構(gòu)造函數(shù)是一個(gè)比較好的實(shí)踐法則。
建造者模式的概念聽上去有點(diǎn)抽象,但是實(shí)際上可以這么說,基本上大家都用過,只是可能自己不知道這就是建造者模式而已。
二、建造者模式角色
1??產(chǎn)品(Product):要?jiǎng)?chuàng)建的產(chǎn)品對(duì)象。
public class Product {
private String name;
private Integer val;
Product(String name, Integer val) {
this.name = name;
this.val = val;
}
@Override
public String toString() {
return "Product is " + name + " value is " + val;
}
}
2??抽象建造者(Builder):建造者的抽象類,規(guī)范產(chǎn)品對(duì)象的各個(gè)組成部分的建造,一般由子類實(shí)現(xiàn)具體建造過程。
public abstract class Builder {
protected Integer val;
protected String name;
// 設(shè)置產(chǎn)品不同部分,以獲得不同的產(chǎn)品
public abstract void setVal(Integer val);
// 設(shè)置名字 公用方法
public void setName(String name) {
this.name = name;
}
// 建造產(chǎn)品
public abstract Product buildProduct();
}
3??具體建造者(ConcreteBuilder):具體的 Builder 類,根據(jù)不同的業(yè)務(wù)邏輯,具體到各個(gè)對(duì)象的各個(gè)組成部分的建造。
public class ConcreteBuilder extends Builder {
@Override
public void setVal(Integer val) {
this.val = val + 100;
}
@Override
// 組建一個(gè)產(chǎn)品
public Product buildProduct() {
// 此處還可以寫特殊的校驗(yàn)邏輯
return new Product(name, val);
}
}
4??調(diào)用者(Director):調(diào)用具體的建造者來創(chuàng)建各個(gè)對(duì)象的各個(gè)部分。
public class Director {
private Builder builder = new ConcreteBuilder();
public Product getAProduct() {
// 設(shè)置不同的零件,產(chǎn)生不同的產(chǎn)品
builder.setName("ProductA");
builder.setVal(2);
return builder.buildProduct();
}
}
三、示例
在設(shè)計(jì)模式中對(duì) Builder Pattern 的定義是用于構(gòu)建復(fù)雜對(duì)象的一種模式,所構(gòu)建的對(duì)象往往需要多步初始化或賦值才能完成。在實(shí)際的開發(fā)過程中,使用 Builder Pattern 來替代多參數(shù)構(gòu)造函數(shù)是一個(gè)比較好的實(shí)踐法則。
常常遇到編寫一個(gè)這樣的實(shí)現(xiàn)類,這個(gè)類擁有多個(gè)構(gòu)造函數(shù):
DoContact(String name);
DoContact(String name, int age);
DoContact(String name, int age, String address);
DoContact(String name, int age, String address, int cardID);
這樣一系列的構(gòu)造函數(shù)主要目的就是為了提供給客戶更多的調(diào)用選擇,以處理不同的構(gòu)造請(qǐng)求。這種方法很常見,很有效力,但缺點(diǎn)也很多:
1??類的作者不得不書寫多種參數(shù)組合的構(gòu)造函數(shù),而且其中還需要設(shè)置默認(rèn)參數(shù)值,這是一個(gè)細(xì)心而又枯燥的工作。
2??其次,這樣的構(gòu)造函數(shù)靈活性也不高,而且在調(diào)用時(shí)不得不提供一些沒有意義的參數(shù)值,例如,DoDoContact("Ace", -1, "SH"),顯然年齡為負(fù)數(shù)沒有意義,但是又不得不這樣做,以符合 Java 的規(guī)范。如果這樣的代碼發(fā)布后,后面的維護(hù)者就會(huì)很頭痛,因?yàn)楦静恢肋@個(gè) -1 是什么含義。
對(duì)于這樣的情況,就非常適合使用 Builder Pattern。Builder Pattern的要點(diǎn)就是通過一個(gè)代理來完成對(duì)象的構(gòu)建過程。這個(gè)代理職責(zé)就是完成構(gòu)建的各個(gè)步驟,同時(shí)它也是易擴(kuò)展的。下面是改寫自 Effective Java 里面的一段代碼:
public class DoContact {
private final int age;
private final int safeID;
private final String name;
private final String address;
public int getAge() {
return age;
}
public int getSafeID() {
return safeID;
}
public String getName() {
return name;
}
public String getAddress() {
return address;
}
public static class Builder {
private int age = 0;
private int safeID = 0;
private String name = null;
private String address = null;
// 構(gòu)建的步驟
public Builder(String name) {
this.name = name;
}
public Builder age(int val) {
this.age = val;
return this;
}
public Builder safeID(int val) {
this.safeID = val;
return this;
}
public Builder address(String val) {
this.address = val;
return this;
}
// 構(gòu)建,返回一個(gè)新對(duì)象
public DoContact build() {
return new DoContact(this);
}
}
private DoContact(Builder b) {
age = b.age;
safeID = b.safeID;
name = b.name;
address = b.address;
}
}
最終,調(diào)用者可以很靈活的去構(gòu)建這個(gè)對(duì)象:
public class kfd {
public static void main(String[] args) {
DoContact object = new DoContact.Builder("MChopin").age(18)
.address("shanghai").build();
System.out.println("name=" + object.getName() + " age=" + object.getAge()
+ " address=" + object.getAddress());
}
}
四、建造者模式優(yōu)缺點(diǎn)
1??優(yōu)點(diǎn)
- 封裝性好,創(chuàng)建和使用分離
- 擴(kuò)展性好,建造類之間獨(dú)立,一定程度上實(shí)現(xiàn)了解耦
2??缺點(diǎn)
- 產(chǎn)生多余的 Builder 對(duì)象
- 產(chǎn)品內(nèi)部發(fā)生變化時(shí),建造者都需要修改,成本較大
五、建造者模式和工廠模式區(qū)別
建造者模式優(yōu)點(diǎn)類似于工廠模式,都是用來創(chuàng)建一個(gè)對(duì)象,但是有很大的區(qū)別,主要區(qū)別如下:
1??建造者模式更加注重方法的調(diào)用順序,工廠模式注重于創(chuàng)建完整對(duì)象。
2??建造者模式根據(jù)不同的產(chǎn)品零件和順序可以創(chuàng)造出不同的產(chǎn)品,而工廠模式創(chuàng)建出來的產(chǎn)品都是一樣的。
3??建造者模式使用者需要知道這個(gè)產(chǎn)品有哪些零件組成,而工廠模式的使用者不需要知道,直接創(chuàng)建就行。