前言
建造者模式又被稱呼爲生成器模式,這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。
使用多個簡單的對象一步一步構建成一個複雜的對象,有點像造房子一樣一步步從地基做起到萬丈高樓。我想這也是爲什麼被稱呼爲建造者模式的原因吧!反正我是找不出更好的理由了。這樣理解反而更容易記住。不好意思,廢話有點多了,且看下文如何分解!!!
一、簡介
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
七、內容推薦
簡書:
相關文章:
如果你覺得我寫的不錯或者對您有所幫助的話。不妨頂一個【微笑】,別忘了點贊、收藏、加關注哈!!
您的每個舉動都是對我莫大的支持