開篇廢話
周末因懶的原因饲趋,停更了兩天果覆。今天主要研究建造者模式。暢游各大博客網(wǎng)站横侦,推薦一篇關(guān)于建造者模式的博客http://blog.csdn.net/self_study/article/details/51707029,簡單明了绰姻,條例清晰枉侧。如果看不懂我寫的,可以嘗試去看看別人的狂芋。榨馁。。
什么是建造者模式
講建造者模式银酗,這里要提取幾個關(guān)鍵詞:
- 復(fù)雜對象: 這里簡單的體現(xiàn)可以理解為辆影,這里對象的成員數(shù)量很多,所以它很復(fù)雜黍特。
- 構(gòu)建過程: 對成員對象進行賦值,業(yè)務(wù)邏輯生成等一系列使之成為一個成熟的對象锯蛀。
- 表示: 返回這個對象灭衷。
- 構(gòu)建過程與表示分離: 一般來說,對成員對象的賦值通常在構(gòu)造函數(shù)中旁涤,這種方式除了不夠靈活之外翔曲,還有就是如果成員對象過多,因為構(gòu)造函數(shù)就會顯得十分臃腫劈愚。所以瞳遍,我們可以將構(gòu)建過程(簡單的理解為賦值,這里不嚴謹菌羽,只是為了幫助理解概念)封裝成獨立的方法掠械,然后再返回整個需要的實例對象。
那么建造者模式:就是為了解決生成復(fù)雜對象的問題,主要通過將構(gòu)建過程與表示分離的方法猾蒂。
如何實現(xiàn)建造者模式
理解了建造者模式后均唉,我們來實現(xiàn)它,就相對簡單了肚菠。
首先盜圖一張:
可以看到舔箭,這里呈現(xiàn)了四個類,有時候?qū)嶋H開發(fā)中會將這個模型進行簡化蚊逢,我們這里先學(xué)習(xí)理論层扶,因為實際操作時,靈活變動太多了烙荷,不適合講解怒医。但是萬變不離其宗,核心思想就是這些奢讨。
- Product稚叹,都稱這個為產(chǎn)品類,說白了就是我需要生成的類拿诸。
- Builder類扒袖,這是一個抽象類或者接口,用來規(guī)定構(gòu)建對象的所需方法亩码。
- ConcreteBuilder 對builder的抽象方法的實現(xiàn)類季率,通常對其優(yōu)化為product的內(nèi)部類,從而省掉builder的定義描沟。常見的有 AlertDialog.Builder 飒泻。
- Director 調(diào)用concrete的方法的類。一般來說吏廉,使用的建造者模式時泞遗,這個也給省了。
我們先來看一個完整版的席覆。以造汽車為例史辙,現(xiàn)在我們需要一輛,有四個輪子佩伤,有四個座椅聊倔,有防風(fēng)玻璃,有方向盤生巡,發(fā)動機等等(這里只列舉這幾樣)耙蔑。
- 首先我們先看Product類,就是我們要生成的復(fù)雜對象孤荣,這里就是指小汽車甸陌。
public class Car {
List<String> tyres = new ArrayList<>();
List<String> carMounts = new ArrayList<>();
String glass;
String steeringWheel;
String engine;
public void setTyres(String tyres) {
this.tyres.add(tyres);
}
public void setCarMounts(String carMounts) {
this.carMounts.add(carMounts);
}
public void setGlass(String glass) {
this.glass = glass;
}
public void setSteeringWheel(String steeringWheel) {
this.steeringWheel = steeringWheel;
}
public void setEngine(String engine) {
this.engine = engine;
}
public List<String> getTyres() {
return tyres;
}
public List<String> getCarMounts() {
return carMounts;
}
public String getGlass() {
return glass;
}
public String getSteeringWheel() {
return steeringWheel;
}
public String getEngine() {
return engine;
}
}
這里可以看到小汽車有五個屬性须揣,然后通過setter和getter方法來對屬性賦值。
- 然后我們先看Builder類邀层,這是一個抽象類或者接口返敬,具體使用看情況而定,我今天想用接口表示:
public interface Builder {
public void buildeTyre(int wheelNumber);
public void buildCarMounts(int carMountsNumber);
public void buildGalss();
public void buildSteeringWheel();
public void buildEngine();
public Car build();
}
這里定義了五個造小汽車零件的方法寥院,和一個生成對象方法劲赠,因為你不能只造這些零件,還需要把這些零件給組裝起來啊秸谢。
- 緊接著我們需要ConcreteBuilder類來實現(xiàn)這些方法啊凛澎,畢竟我們是實干家,不能光說不做估蹄!concretebuilder
public class CarBuilder implements Builder {
Car car = new Car();
@Override
public void buildeTyre(int wheelNumber) {
for (int i = 0; i < wheelNumber; i++) {
car.setTyres("已經(jīng)造了" + i + "輪子了");
}
}
@Override
public void buildCarMounts(int carMountsNumber) {
for (int i = 0; i < carMountsNumber; i++) {
car.setCarMounts("已經(jīng)造了" + i + "椅子了");
}
}
@Override
public void buildGalss() {
car.setGlass("防風(fēng)玻璃做好了");
}
@Override
public void buildSteeringWheel() {
car.setSteeringWheel("方向盤做好了");
}
@Override
public void buildEngine() {
car.setEngine("發(fā)動機已經(jīng)做好了");
}
@Override
public Car build() {
return car;
}
}
這里實現(xiàn)了builder接口塑煎,沒什么好說的,值得注意的就是臭蚁,在CarBuilder類中最铁,維護了一個Car對象,實現(xiàn)的所有方法中垮兑,去調(diào)用Car的set方法冷尉,最后build()方法中去返回這個對象。
此時此刻系枪,我們已經(jīng)能通過CarBuilder類去建造我們所需要的Car對象了雀哨。但是畢竟造汽車的工序是及其復(fù)雜了,因為我們這里只簡單的列舉了五項私爷,可能感覺還是比較輕松的雾棺,但是,如果有上百道工序的話衬浑,難道我們需要每次去造小車的時候都去調(diào)用這上百個方法嗎捌浩。顯然,這里構(gòu)建的過程嚎卫,我們希望是不透明的嘉栓,那么我們可以將這個步驟封裝起來,于是就有了Director類的出現(xiàn)拓诸。
- 我們希望有一個技術(shù)總工來調(diào)度負責(zé)整個造車的過程。
public class AodiDirecter {
private Builder builder;
public AodiDirecter(Builder builder) {
this.builder = builder;
}
public void construct() {
builder.buildeTyre(4);
builder.buildCarMounts(4);
builder.buildEngine();
builder.buildGalss();
builder.buildSteeringWheel();
}
}
這樣整個建造者模式就完成了麻昼,而我們需要一個奧迪車時奠支,只需要:
public class Buyer {
public void buy() {
Builder builder = new CarBuilder();
AodiDirecter director = new AodiDirecter(builder);
director.construct();
Car aodiCar = builder.build();
}
}
如果說,builder是產(chǎn)線工人們抚芦,AodiDirecter 就可以理解為奧迪工程師倍谜,工人們只知道制造器件迈螟,工程師來統(tǒng)籌設(shè)計造車的工序,安排下去后尔崔,工人們按命令執(zhí)行就行了答毫。而對于買家來說,我并看不到你是怎么造的季春,反正我只要結(jié)果就行了洗搂。
但是這樣往往會很麻煩,我們通常會對其進行精簡優(yōu)化载弄。
看上面對建造者定義了四個功能模塊耘拇,在實現(xiàn)過程中,是不是有一些宇攻,何必多此一舉的感覺惫叛。這里我盜用了別人的代碼,工作繁忙(太懶了)還請諒解逞刷。
public class Computer {
private String CPU;
private String GPU;
private String memoryType;
private int memorySize;
private String storageType;
private int storageSize;
private String screenType;
private float screenSize;
private String OSType;
public static class Builder {
// Optional parameters - initialize with default values
private String CPU = "inter-i3";
private String GPU = "GTX-960";
private String memoryType = "ddr3 1666MHz";
private int memorySize = 8;//8GB
private String storageType = "hdd";
private int storageSize = 1024;//1TB
private String screenType = "IPS";
private float screenSize = 23.8f;
private String OSType = "Windows 10";
public Builder() {
}
public Builder setCPU(String CPU) {
this.CPU = CPU;
return this;
}
public Builder setGPU(String GPU) {
this.GPU = GPU;
return this;
}
public Builder setMemoryType(String memoryType) {
this.memoryType = memoryType;
return this;
}
public Builder setMemorySize(int memorySize) {
this.memorySize = memorySize;
return this;
}
public Builder setStorageType(String storageType) {
this.storageType = storageType;
return this;
}
public Builder setStorageSize(int storageSize) {
this.storageSize = storageSize;
return this;
}
public Builder setScreenType(String screenType) {
this.screenType = screenType;
return this;
}
public Builder setScreenSize(float screenSize) {
this.screenSize = screenSize;
return this;
}
public Builder setOSType(String OSType) {
this.OSType = OSType;
return this;
}
public Computer create() {
return new Computer(this);
}
}
private Computer(Builder builder) {
CPU = builder.CPU;
GPU = builder.GPU;
memoryType = builder.memoryType;
memorySize = builder.memorySize;
storageType = builder.storageType;
storageSize = builder.storageSize;
screenType = builder.screenType;
screenSize = builder.screenSize;
OSType = builder.OSType;
}
}
可以看到嘉涌,整個建造者模式就是一個類,然而這個類中存在一個靜態(tài)內(nèi)部類Builder夸浅,這個Builder仑最,其實對應(yīng)的是建造者模式中的concreteBuilder,Computer對應(yīng)的就是我們product题篷。去掉了Builder抽象類甩苛,因為直接實現(xiàn)了。同時還缺少了Directer猴仑,因為這里的設(shè)計是暴露構(gòu)建細節(jié)村砂,所以就不需要了。
這種方式的好處就是葫笼,過程可控深啤。我們來看看調(diào)用。
Computer computer = new Computer.Builder()
.setCPU("inter-skylake-i7")
.setGPU("GTX-Titan")
.setMemoryType("ddr4-2133MHz")
.setMemorySize(16)
.setStorageType("ssd")
.setStorageSize(512)
.setScreenType("IPS")
.setScreenSize(28)
.setOSType("Ubuntu/Window10")
.create();
這是一種鏈?zhǔn)秸{(diào)用路星,也是我們常見的建造者模式溯街。我們可以對每個成員對象進行控制,從而得到我們想要的product洋丐。當(dāng)然呈昔,我們看回Computer類的實現(xiàn),發(fā)現(xiàn)友绝,每個成員對象都是有個默認值的堤尾。也就是說,你完全可以通過new Computer.Builder().create()來獲取默認的實例對象迁客,這基本就是Directer的功能郭宝。所以精簡下來辞槐,發(fā)現(xiàn)建造者模式還是挺實用的。
然而在大型的系統(tǒng)中粘室,精簡版的建造者模式榄檬,并不是很適用,因為它的針對性太強衔统,往往呈現(xiàn)出來的是同一種產(chǎn)品鹿榜,拓展性并不是很好,而我們使用原始版的話缰冤,可以對Directer進行拓展犬缨,可以更加多元靈活。