Java 設計模式——建造者模式(Builder Pattern)
前言
建造者模式又被稱呼為生成器模式,這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。
使用多個簡單的物件一步一步構建成一個複雜的物件,有點像造房子一樣一步步從地基做起到萬丈高樓。我想這也是為什麼被稱呼為建造者模式的原因吧!反正我是找不出更好的理由了。這樣理解反而更容易記住。不好意思,廢話有點多了,且看下文如何分解!!!
一、簡介
1、定義:將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示
2、主要作用:在使用者不知道物件的建造過程和細節的情況下就可以直接建立複雜的物件。
3、如何使用:使用者只需要給出指定複雜物件的型別和內容,建造者模式負責按順序建立複雜物件(把內部的建造過程和細節隱藏起來)
4、解決的問題:
(1)、方便使用者建立複雜的物件(不需要知道實現過程)
(2)、程式碼複用性 & 封裝性(將物件構建過程和細節進行封裝 & 複用)
5、注意事項:與工廠模式的區別是:建造者模式更加關注與零件裝配的順序,一般用來建立更為複雜的物件
哈哈! 本人比較懶,上面特性都是從其他部落格中吸取到的精華,歸納與此,方便以後查閱。
二、實現方式
研究了好久發現關於建造者模式的實現例子有好多,有造人、造車、造房子、造世界的...等好多。但歸類後有兩種實現方式。
(1)通過Client、Director、Builder和Product形成的建造者模式
(2)通過靜態內部類方式實現零件無序裝配話構造
三、常見第一種方式
通過Client、Director、Builder和Product形成的建造者模式
(1)一般有以下幾個角色
抽象建造者(builder):描述具體建造者的公共介面,一般用來定義建造細節的方法,並不涉及具體的物件部件的建立。
具體建造者(ConcreteBuilder):描述具體建造者,並實現抽象建造者公共介面。
指揮者(Director):呼叫具體建造者來建立複雜物件(產品)的各個部分,並按照一定順序(流程)來建造複雜物件。
產品(Product):描述一個由一系列部件組成較為複雜的物件。
(2)舉個例子
既然是建造者模式,那麼我們還是繼續造房吧,其實我也想不到更簡單的例子。
假設造房簡化為如下步驟:(1)地基(2)鋼筋工程(3)鋪電線(4)粉刷
“如果”要蓋一座房子,首先要找一個建築公司或工程承包商(指揮者)。承包商指揮工人(具體建造者)過來造房子(產品),最後驗收。
(3)具體步驟
1、建立抽象建造者定義造房步驟
2、建立工人具體實現造房步驟
3、建立承包商指揮工人施工
4、驗收,檢查是否建造完成
好了,到這裡第一種方法就講解完了。具體步驟都給了,大家可以嘗試寫一下,寫不出來沒關係。
——大家可以複製啊!省時間嘛,但不寫的話更容易忘記。好了廣告打完了,到貼程式碼時間...
(4)具體程式碼
建造者:Builder.java
/**
* Builder.java
* 建造者
*/
abstract class Builder {
//地基
abstract void bulidA();
//鋼筋工程
abstract void bulidB();
//鋪電線
abstract void bulidC();
//粉刷
abstract void bulidD();
//完工-獲取產品
abstract Product getProduct();
}
產品:Product.java
/**
* Product.java
* 產品(房子)
*/
public class Product {
private String buildA;
private String buildB;
private String buildC;
private String buildD;
public String getBuildA() {
return buildA;
}
public void setBuildA(String buildA) {
this.buildA = buildA;
}
public String getBuildB() {
return buildB;
}
public void setBuildB(String buildB) {
this.buildB = buildB;
}
public String getBuildC() {
return buildC;
}
public void setBuildC(String buildC) {
this.buildC = buildC;
}
public String getBuildD() {
return buildD;
}
public void setBuildD(String buildD) {
this.buildD = buildD;
}
@Override
public String toString() {
return buildA+"\n"+buildB+"\n"+buildC+"\n"+buildD+"\n"+"房子驗收完成";
}
}
具體建造者:ConcreteBuilder.java
/**
* ConcreteBuilder.java
* 具體建造者(工人)
*/
public class ConcreteBuilder extends Builder{
private Product product;
public ConcreteBuilder() {
product = new Product();
}
@Override
void bulidA() {
product.setBuildA("地基");
}
@Override
void bulidB() {
product.setBuildB("鋼筋工程");
}
@Override
void bulidC() {
product.setBuildC("鋪電線");
}
@Override
void bulidD() {
product.setBuildD("粉刷");
}
@Override
Product getProduct() {
return product;
}
}
指揮者:Director.java
/**
* Director.java
* 指揮者
*/
public class Director {
//指揮工人按順序造房
public Product create(Builder builder) {
builder.bulidA();
builder.bulidB();
builder.bulidC();
builder.bulidD();
return builder.getProduct();
}
}
測試類:Test.java
/**
* Test.java
* 測試類
*/
public class Test {
public static void main(String[] args) {
Director director = new Director();
Product create = director.create(new ConcreteBuilder());
System.out.println(create.toString());
}
}
程式碼貼完了,有沒有感覺,看程式碼比看文字好多了。嗯嗯 我也是這麼覺得 可惜不能光貼程式碼。不然我一天可以寫10篇了T-T。
三、第二種方式
通過靜態內部類方式實現零件無序裝配話構造:案例:Android中的AlertDialog
這種方式使用更加靈活,更符合定義。內部有複雜物件的預設實現,使用時可以根據使用者需求自由定義更改內容,並且無需改變具體的構造方式。就可以生產出不同複雜產品
(1)主要有三個角色:抽象建造者、具體建造者、產品
比第一種方式少了指揮者,主要是因為第二種方式把指揮者交給使用者來操作,使得產品的建立更加簡單靈活。
(2)舉個例子
比如麥當勞的套餐,服務員(具體建造者)可以隨意搭配任意幾種產品(零件)組成一款套餐(產品),然後出售給客戶。
(3)具體步驟
1、建立建造者定義麥當勞的產品
2、建立服務員實現具體產品
3、服務員隨意搭配套餐出售給客戶
(4)具體程式碼
建造者:Builder.java
/**
* Builder.java
* 建造者
*/
abstract class Builder {
//漢堡
abstract Builder bulidA(String mes);
//飲料
abstract Builder bulidB(String mes);
//薯條
abstract Builder bulidC(String mes);
//甜品
abstract Builder bulidD(String mes);
//獲取套餐
abstract Product build();
}
產品:Product.java
/**
* Product.java
* 產品(麥當勞套餐)
*/
public class Product {
private String buildA="漢堡";
private String buildB="飲料";
private String buildC="薯條";
private String buildD="甜品";
public String getBuildA() {
return buildA;
}
public void setBuildA(String buildA) {
this.buildA = buildA;
}
public String getBuildB() {
return buildB;
}
public void setBuildB(String buildB) {
this.buildB = buildB;
}
public String getBuildC() {
return buildC;
}
public void setBuildC(String buildC) {
this.buildC = buildC;
}
public String getBuildD() {
return buildD;
}
public void setBuildD(String buildD) {
this.buildD = buildD;
}
@Override
public String toString() {
return buildA+"\n"+buildB+"\n"+buildC+"\n"+buildD+"\n"+"組成套餐";
}
}
具體建造者:ConcreteBuilder.java
/**
* ConcreteBuilder.java
* 具體建造者(服務員)
*/
public class ConcreteBuilder extends Builder{
private Product product;
public ConcreteBuilder() {
product = new Product();
}
@Override
Product build() {
return product;
}
@Override
Builder bulidA(String mes) {
product.setBuildA(mes);
return this;
}
@Override
Builder bulidB(String mes) {
product.setBuildB(mes);
return this;
}
@Override
Builder bulidC(String mes) {
product.setBuildC(mes);
return this;
}
@Override
Builder bulidD(String mes) {
product.setBuildD(mes);
return this;
}
}
測試類:Test.java
/**
* Test.java
* 測試類
*/
public class Test {
public static void main(String[] args) {
ConcreteBuilder concreteBuilder = new ConcreteBuilder();
Product build = concreteBuilder
.bulidA("牛肉煲")
// .bulidC("全家桶")
.bulidD("冰淇淋")
.build();
System.out.println(build.toString());
}
}
突然發現貼程式碼也是一個技術活,一不小心就貼了一晚上。唉唉唉,又熬夜了啊,我可憐的頭髮
四、總結
(1)優點
1、產品的建造和表示分離,實現瞭解耦。
2、將複雜產品的建立步驟分解在不同的方法中,使得建立過程更加清晰
3、增加新的具體建造者無需修改原有類庫的程式碼,易於拓展,符合“開閉原則“。
(2)缺點
1、產品必須有共同點,限制了使用範圍。
2、如內部變化複雜,會有很多的建造類,難以維護。
(3)應用場景
1、需要生成的產品物件有複雜的內部結構,這些產品物件具備共性;
2、隔離複雜物件的建立和使用,並使得相同的建立過程可以建立不同的產品。
3、需要生成的物件內部屬性本身相互依賴。
4、適合於一個具有較多的零件(屬性)的產品(物件)的建立過程。
五、Demo地址
https://github.com/DayorNight/DesignPattern
六、參考文件
https://www.jianshu.com/p/be290ccea05a
http://www.runoob.com/design-pattern/builder-pattern.html
https://www.cnblogs.com/lwbqqyumidi/p/3742562.html
七、內容推薦
簡書:
相關文章:
如果你覺得我寫的不錯或者對您有所幫助的話。不妨頂一個【微笑】,別忘了點贊、收藏、加關注哈!!
您的每個舉動都是對我莫大的支援