本文根據光頭強做電鋸的故事,講解一下Java設計模式中的“建造者模式”,故事性更強,配合著程式碼講解,讓大家更輕鬆的掌握“建造者模式”。
一、故事背景
(一)什麼是建造者模式?
建造者模式它是一種將複雜物件的構造與其表示分開,以便相同的構造過程可以建立不同的表示
的設計模式。
(二)基本組成單元有哪些?
一個完整的建造者模式分為4個部分:
- 1.建造者(Builder):用於建立Product物件的部分的抽象介面。
- 2.具體建造者(ConcreteBuilder):通過實現Builder介面構建和組裝產品的一部分。
- 3.指揮者(Director):它直接Builder介面來構造物件。
- 4.產品(Product):需要構建的複雜的物件。
(三)使用場景
一般用於複雜的物件內部,比如:一個物件有多個功能,可以在它的內部用多個方法具體描述每個功能,然後呼叫這個類的時候,就可以直自由的構建出這個類物件(比如:new Person().setName("18").setAge(20).build();
其實這個Person類就做了具體的物件構建的操作邏輯。),也有網友狹隘的說鏈式呼叫
就是建造者模式,其實那是片面的認識,雖然是一種表現形式,但是實際操作中有很多不同的表現形式,不能一概而論。下面就一個例項詳解一下基本使用到複雜多變的使用場景。
二、基本使用場景
(一)各個類的介紹:
光頭強於是去了鎮子上的五金店鋪,,光頭強心理嘀咕著:“不光能砍樹,還能嚇跑熊大熊二,看它還敢來欺負自己。”於是跟那個老闆的說了自己的需求:“我要買一把電手鋸”。老闆說:“不好意思,沒有了,需要預定,預計一個星期之後就到了。”然後光頭強就下單了,老闆就電話通知手電鋸工廠下了訂單,然後工廠開始生產手電鋸。
這回還沒把熊大熊二嚇跑,於是光頭強又跑到鎮子上,找到了五金店的老闆,讓老闆給他一把厲害的鋸子。光頭強這回跟那個老闆的說了自己的需求:“我要一把厲害的電手鋸,上回那個沒有趕走熊大熊二,你這裡有沒有厲害的手電鋸”。老闆逐個都介紹了一遍,光頭強一對比,發現並沒有自己想要的獨一無二的那個。於是跟那個老闆的說了自己的需求:“我需要的是這樣的:調速防誤觸智慧開關、動力強耐高溫散熱好的純銅電機、環保大容量鋰電池、人體工體學包膠防滑防抖手柄、環保防觸電插頭、加厚加固耐磨抗打擊防護罩、高硬度鋸片、然後額外配上LED燈,錢不是問題”。老闆說沒問題,半個月之後過來取吧。光頭強於是交了定金,興奮的回家了。坐等老闆的好訊息了。
車間要準備要投入生產的機器,還有各種原材料和模具:
/**
* 鏈鋸建築者
*/
public interface ChainsawBuilder {
// 蓄電池
void battery();
// 電動機
void motor();
// 減速箱
void reductionGearbox();
// 防護罩
void hood();
// 手柄
void handle();
// 開關
void switches();
// 插頭
void plug();
// 圓鋸片
void circularSaw();
// 獲取鏈鋸(產品)的例項
Chainsaws getChainsaws();
}
複製程式碼
接下來就是具體的車間按照現有的材料進行生產:
/**
* 鏈鋸建築者(具體建築者)
*/
public class ChainsawBuilderImpl implements ChainsawBuilder{
private Chainsaws chainsaws;
public ChainsawBuilderImpl() {
chainsaws = new Chainsaws();
}
@Override
public void battery() {
chainsaws.setBattery("普通鋰電池");
}
@Override
public void motor() {
chainsaws.setMotor("普通鋁電動機");
}
@Override
public void reductionGearbox() {
chainsaws.setReductionGearbox("普通減速箱");
}
@Override
public void hood() {
chainsaws.setHood("普通PVC塑料");
}
@Override
public void handle() {
chainsaws.setHandle("普通PVC塑料");
}
@Override
public void switches() {
chainsaws.setSwitches("普通拉線開關");
}
@Override
public void plug() {
chainsaws.setPlug("普通三口插頭");
}
@Override
public void circularSaw() {
chainsaws.setCircularSaw("普通鋼鋸片");
}
@Override
public Chainsaws getChainsaws() {
return chainsaws;
}
}
複製程式碼
最終產品就具備這些功能:
/**
* 產品(鏈鋸)
*/
public class Chainsaws {
// 蓄電池
private String battery;
// 電動機
private String motor;
// 減速箱
private String reductionGearbox;
// 防護罩
private String hood;
// 手柄
private String handle;
// 開關
private String switches;
// 插頭
private String plug;
// 圓鋸片
private String circularSaw;
public String getBattery() {
return battery;
}
public void setBattery(String battery) {
this.battery = battery;
}
public String getMotor() {
return motor;
}
public void setMotor(String motor) {
this.motor = motor;
}
public String getReductionGearbox() {
return reductionGearbox;
}
public void setReductionGearbox(String reductionGearbox) {
this.reductionGearbox = reductionGearbox;
}
public String getHood() {
return hood;
}
public void setHood(String hood) {
this.hood = hood;
}
public String getHandle() {
return handle;
}
public void setHandle(String handle) {
this.handle = handle;
}
public String getSwitches() {
return switches;
}
public void setSwitches(String switches) {
this.switches = switches;
}
public String getPlug() {
return plug;
}
public void setPlug(String plug) {
this.plug = plug;
}
public String getCircularSaw() {
return circularSaw;
}
public void setCircularSaw(String circularSaw) {
this.circularSaw = circularSaw;
}
@Override
public String toString() {
return "Chainsaws{" +
"\n battery='" + battery + '\'' +
", motor='" + motor + '\'' +
", reductionGearbox='" + reductionGearbox + '\'' +
", hood='" + hood + '\'' +
", handle='" + handle + '\'' +
", switches='" + switches + '\'' +
", plug='" + plug + '\'' +
", circularSaw='" + circularSaw + '\'' +
"鏈鋸已經做好了\n" + '}';
}
}
複製程式碼
老闆作為一箇中間人的角色,需要跟廠商對接,電話通知建造方,檢視進度如何了:
/**
* 五金店老闆(驗收方)
*/
public class HardwareStoreBoss {
// 電話通知建造方,檢視進度如何了
public Chainsaws notify(ChainsawBuilder builder){
// 蓄電池
builder.battery();
// 電動機
builder.motor();
// 減速箱
builder.reductionGearbox();
// 防護罩
builder.hood();
// 手柄
builder.handle();
// 開關
builder.switches();
// 插頭
builder.plug();
// 圓鋸片
builder.circularSaw();
return builder.getChainsaws();
}
}
複製程式碼
過了幾天,光頭強打電話給五金店老闆。
HardwareStoreBoss hardwareStoreBoss = new HardwareStoreBoss();
複製程式碼
五金店老闆跟光頭強說你等會兒,我先去問問鏈鋸做好了沒,於是:
Chainsaws chainsaws = hardwareStoreBoss.notify(new ChainsawBuilderImpl());
System.out.println(chainsaws.toString());
複製程式碼
這時候列印結果是:
Chainsaws{
battery='普通鋰電池', motor='普通鋁電動機', reductionGearbox='普通減速箱', hood='普通PVC塑料', handle='普通PVC塑料', switches='普通拉線開關', plug='普通三口插頭', circularSaw='普通鋼鋸片'鏈鋸已經做好了
}
複製程式碼
然後五金店老闆去生產那裡取貨,然後再通知光頭強過去取貨。
(二)UML圖解如下:
三、新增建造者介面(換一個新鏈鋸)
(一)各個類的介紹:
光頭強拿到貨之後,就興高采烈的去試著砍樹,結果發現砍了幾棵樹,要麼就是沒電了,要麼就是掉鏈子了,這怎麼行?光頭強這回要求老闆退貨,老闆不幹,這樣吧。我給你返回維修。維修費我出。光頭強不幹,堅決要退貨,老闆犟不過,要不這樣,給你換一個效能更高階的鏈鋸,你只要補差價就好了,怎麼樣,工廠那邊正好有批次在做的,給你預定一個,一週內可以就拿到貨了。光頭強爽快的答應了。
於是工廠這邊也利用原有的功能(介面ChainsawBuilder),加入新的一些功能(新建一個類ChainsawBuilderImpl2),就開始製造了。基本功能都差不多的,只是換一些零部件,如下所示:
/**
* 鏈鋸建築者(具體建築者)
*/
public class ChainsawBuilderImpl2 implements ChainsawBuilder{
private Chainsaws chainsaws;
public ChainsawBuilderImpl2() {
chainsaws = new Chainsaws();
}
@Override
public void battery() {
chainsaws.setBattery("環保大容量鋰電池");
}
@Override
public void motor() {
chainsaws.setMotor("動力強耐高溫散熱好的純銅電機");
}
@Override
public void reductionGearbox() {
chainsaws.setReductionGearbox("減震變頻高功率變速箱");
}
@Override
public void hood() {
chainsaws.setHood("加厚加固耐磨抗打擊防護罩");
}
@Override
public void handle() {
chainsaws.setHandle("人體工體學包膠手柄");
}
@Override
public void switches() {
chainsaws.setSwitches("調速防誤觸智慧開關");
}
@Override
public void plug() {
chainsaws.setPlug("環保防觸電插頭");
}
@Override
public void circularSaw() {
chainsaws.setCircularSaw("高硬度鋸片");
}
@Override
public Chainsaws getChainsaws() {
return chainsaws;
}
}
複製程式碼
同樣的過了幾天,光頭強打電話給五金店老闆。
HardwareStoreBoss hardwareStoreBoss = new HardwareStoreBoss();
複製程式碼
五金店老闆跟光頭強說你等會兒,我先去問問鏈鋸(這時候是:新鏈鋸)做好了沒,於是:
Chainsaws chainsaws = hardwareStoreBoss.notify(new ChainsawBuilderImpl2());
System.out.println(chainsaws.toString());
複製程式碼
這時候列印結果是:
Chainsaws{
battery='環保大容量鋰電池', motor='動力強耐高溫散熱好的純銅電機', reductionGearbox='減震變頻高功率變速箱', hood='加厚加固耐磨抗打擊防護罩', handle='人體工體學包膠手柄', switches='調速防誤觸智慧開關', plug='環保防觸電插頭', circularSaw='高硬度鋸片'鏈鋸已經做好了
}
複製程式碼
於是光頭強就去拿到新鏈鋸愉快的砍樹去了。
(二)UML圖解如下:
四、減少指揮者角色(光頭強聯絡廠家定製)
(一)各個類的介紹:
光頭強發現一個鏈鋸不夠用了,還想再買一個,但是每次通過五金店老闆去詢問太麻煩了,於是通過網上官網查詢,找到了生產廠家的售後電話,直接聯絡他們,又重新定製了一個鏈鋸。
廠家看光頭強已經是第三次購買,算是VIP使用者了,特意為他開了一個後門,車間有同意協調(鏈鋸建造者類)專門管理。
/**
* 鏈鋸建築者
*/
public interface ChainsawBuilder {
// 蓄電池
ChainsawBuilder battery(String name);
// 電動機
ChainsawBuilder motor(String name);
// 減速箱
ChainsawBuilder reductionGearbox(String name);
// 防護罩
ChainsawBuilder hood(String name);
// 手柄
ChainsawBuilder handle(String name);
// 開關
ChainsawBuilder switches(String name);
// 插頭
ChainsawBuilder plug(String name);
// 圓鋸片
ChainsawBuilder circularSaw(String name);
// 獲取鏈鋸(產品)的例項
Chainsaws getChainsaws();
}
複製程式碼
這樣一來,可以快速由專人負責找到對應的零件。
具體的生產建築者這邊也沒閒著,也跟著做了改變,之前是規矩寫死的,我這裡有什麼,客戶才能定製什麼(方法傳入的String型別的引數),現在是可互需要的是什麼,我這邊就負責生產什麼樣的。具體如下:
/**
* 鏈鋸建築者(具體建築者)
*/
public class ChainsawBuilderImpl2 implements ChainsawBuilder {
private Chainsaws chainsaws;
public ChainsawBuilderImpl2() {
chainsaws = new Chainsaws();
}
@Override
public ChainsawBuilder battery(String name) {
chainsaws.setBattery(name);
return this;
}
@Override
public ChainsawBuilder motor(String name) {
chainsaws.setMotor(name);
return this;
}
@Override
public ChainsawBuilder reductionGearbox(String name) {
chainsaws.setReductionGearbox(name);
return this;
}
@Override
public ChainsawBuilder hood(String name) {
chainsaws.setHood(name);
return this;
}
@Override
public ChainsawBuilder handle(String name) {
chainsaws.setHandle(name);
return this;
}
@Override
public ChainsawBuilder switches(String name) {
chainsaws.setSwitches(name);
return this;
}
@Override
public ChainsawBuilder plug(String name) {
chainsaws.setPlug(name);
return this;
}
@Override
public ChainsawBuilder circularSaw(String name) {
chainsaws.setCircularSaw(name);
return this;
}
@Override
public Chainsaws getChainsaws() {
return chainsaws;
}
}
複製程式碼
光頭強這時候想問廠家做好了沒,告訴廠家自己要做的零部件的型別,廠家就一次性安排生產了:
ChainsawBuilderImpl2 chainsawBuilderImpl2 = new ChainsawBuilderImpl2();
Chainsaws chainsaws = chainsawBuilderImpl2.battery("環保大容量鋰電池")
.motor("動力強耐高溫散熱好的純銅電機")
.reductionGearbox("減震變頻高功率變速箱")
.hood("加厚加固耐磨抗打擊防護罩")
.handle("人體工體學包膠手柄")
.switches("調速防誤觸智慧開關")
.plug("環保防觸電插頭")
.circularSaw("高硬度鋸片")
.getChainsaws();
複製程式碼
這時候列印結果還是一樣的:
Chainsaws{
battery='環保大容量鋰電池', motor='動力強耐高溫散熱好的純銅電機', reductionGearbox='減震變頻高功率變速箱', hood='加厚加固耐磨抗打擊防護罩', handle='人體工體學包膠手柄', switches='調速防誤觸智慧開關', plug='環保防觸電插頭', circularSaw='高硬度鋸片'鏈鋸已經做好了
}
複製程式碼