概念
将一個複雜的對象的建構與它的表示分離,使得同樣的建構過程可以有不同的表示。
大概的意思是說:一套的建構過程可以有不同的産品(表示)出來。這些産品(表示)都按照這一套的建構過程被生産出來。
初探
建造者模式屬于建立型模式。比如說:樓房是千差萬别的,樓房的外形,層數,内部房間的數量,房間的裝飾都不一樣。但是對于建造者來說,抽象出來的建築流程是确定的。因為建築一座樓房,都可以歸納為幾個步驟:1打樁、2建地基、3搭架構、4内部建設。同理,建造者設計模式也是基于這樣的概念而生的,這個設計模式用來解決什麼樣的情況呢:即流程不變,但每個流程實作的具體細節是會變化的。這樣的情況,可以考慮使用建造者。就像蓋房子,4個流程都必須有,但每個流程各自的實作細節,各個房子各有不同。 建造者模式的好處就是保證了流程不會變化,即流程不會增加也不會遺漏,也不會産生流程次序的錯誤。而建造者模式,保證了流程的确定性,而流程内部的實作細節,是可繼承擴充的。從根源上解決了流程不規範的問題。
寫代碼的時候,如果你遇到一個需要把控流程,但流程中的實作細節各有許多的方式,你可以采用建造者模式。用一個director類把控流程,而用許多不同的builder去建造流程中的細節并産生産品。這樣,生産出來的産品基本是不會出問題的。因為流程把控好了。你可以有多個builder去負責建造生産産品,而讓director去把控流程。如果有新的産品,但是流程一緻,你可以再擴張出一個builder來。這樣,你看,建造者模式是不是很符合OCP原則呢。
建造者模式注重于房子的零部件的組裝的順序,而工廠模式則注重于建立怎樣的房子.
建造者模式要求建造的過程必須是穩定的,而裝飾模式沒有這個要求
模式中的角色分類
- Builder:給出一個抽象接口,規範建造者對于生産的産品的各個組成部分的建造。這個接口隻是定一個規範,不涉及具體的建造,具體的建造讓繼承于它的子類(ConcreteBuilder)去實作
- ConcreteBuilder:實作builder接口,針對不同的商業邏輯,具體化各對象部分的建造,最後傳回一個建造好的産品。實作抽象類的所有未實作的方法,具體來說一般是兩項任務:組建産品;傳回組建好的産品。
- Director:導演(負責人),顧名思義,負責規範流程之用。在指導中不涉及産品的建立,隻負責保證複雜對象各部分被建立或按某種順序建立。導演類一般不與産品類發生依賴關系,與導演類直接互動的是建造者類。一般來說,導演類被用來封裝程式中易變的部分。
- Product:複雜對象。
角色UML關系圖如下
以建立AlertDialog為例子
目前,建立者模式,有很多變種.
标準模式
UML圖如下
java代碼
抽象接口
package demo10;
/**
*
* @ClassName: DialogBuilder
* @Description:抽象接口
* @author cheng
* @date 2017-8-15 下午02:02:06
*/
public interface DialogBuilder {
/**
*
* @Title: createBackGround
* @Description: 建立背景
* @param s
* @return
*/
DialogBuilder createBackGround(String s);
/**
*
* @Title: createShape
* @Description: 建立形狀
* @param s
* @return
*/
DialogBuilder createShape(String s);
/**
*
* @Title: createTitle
* @Description: 建立标題
* @param s
* @return
*/
DialogBuilder createTitle(String s);
/**
*
* @Title: build
* @Description: 建立對象并傳回
* @return
*/
Object build();
}
具體實作類
package demo10;
/**
*
* @ClassName: AlertDialogBuilder
* @Description:具體建構類
* @author cheng
* @date 2017-8-15 下午02:13:39
*/
public class AlertDialogBuilder implements DialogBuilder {
//持有産品的引用
private AlertDialog alertDialog;
public AlertDialogBuilder() {
alertDialog = new AlertDialog();
}
@Override
public DialogBuilder createBackGround(String s) {
alertDialog.setBackGround(s);
return this;
}
@Override
public DialogBuilder createShape(String s) {
alertDialog.setShape(s);
return this;
}
@Override
public DialogBuilder createTitle(String s) {
alertDialog.setTitle(s);
return this;
}
@Override
public AlertDialog build() {
return alertDialog;
}
}
産品類
package demo10;
/**
*
* @ClassName: AlertDialog
* @Description:産品類
* @author cheng
* @date 2017-8-15 下午02:08:35
*/
public class AlertDialog {
private String backGround;
private String shape;
private String title;
/**
* 複寫
*/
@Override
public String toString() {
return "AlertDialog[backGround=" + backGround + ",shape=" + shape
+ ",title=" + title + "]";
}
public AlertDialog() {
}
public AlertDialog(String backGround, String shape, String title) {
super();
this.backGround = backGround;
this.shape = shape;
this.title = title;
}
public String getBackGround() {
return backGround;
}
public void setBackGround(String backGround) {
this.backGround = backGround;
}
public String getShape() {
return shape;
}
public void setShape(String shape) {
this.shape = shape;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
導演類
package demo10;
/**
*
* @ClassName: DialogDirector
* @Description:導演類
* @author cheng
* @date 2017-8-15 下午02:19:11
*/
public class DialogDirector {
// 持有抽象接口的引用
private DialogBuilder dialogBuilder;
public DialogDirector() {
dialogBuilder = new AlertDialogBuilder();
}
public AlertDialog createDialog(String background, String shape,
String title) {
return (AlertDialog) dialogBuilder.createBackGround(background)
.createShape(shape).createTitle(title).build();
}
}
測試
package demo10;
/**
*
* @ClassName: ClientTest
* @Description:測試
* @author cheng
* @date 2017-8-15 下午02:21:52
*/
public class ClientTest {
public static void main(String[] args) {
AlertDialog alertDialog1 = new DialogDirector().createDialog("黑色",
"長方形", "是否删除");
System.out.println(alertDialog1);
}
}
運作結果
鍊式簡版
隻包括建造者類,産品參數内部類,産品類
UML圖如下
java代碼
具體建造類
package demo11;
/**
*
* @ClassName: AlertDialogBuilder
* @Description:具體建構類
* @author cheng
* @date 2017-8-15 下午02:13:39
*/
public class AlertDialogBuilder {
private AlertDialogParams alertDialogParams;
/**
* 初始化建造者,初始化AlertDialogparams中間件
*/
public AlertDialogBuilder() {
alertDialogParams = new AlertDialogParams();
}
/**
*
* @ClassName: AlertDialogparams
* @Description:内部類來作為中間量,作為建造對象的參數傳入,屬性和産品類相同
* @author cheng
* @date 2017-8-15 下午03:58:21
*/
class AlertDialogParams {
String backGround;
String shape;
String title;
}
/**
*
* @Title: createBackGround
* @Description: 傳回自身AlertDialogBuilder,鍊式調用
* @param s
* @return
*/
public AlertDialogBuilder createBackGround(String s) {
alertDialogParams.backGround = s;
return this;
}
public AlertDialogBuilder createShape(String s) {
alertDialogParams.shape = s;
return this;
}
public AlertDialogBuilder createTitle(String s) {
alertDialogParams.title = s;
return this;
}
/**
* 建立AlertDialog對象,将中間量alertDialogParams傳入AlertDialog,進行建構.
*/
public AlertDialog build() {
AlertDialog alertDialog = new AlertDialog();
alertDialog.init(alertDialogParams);
return alertDialog;
}
}
産品類
package demo11;
/**
*
* @ClassName: AlertDialog
* @Description:産品類
* @author cheng
* @date 2017-8-15 下午03:50:09
*/
public class AlertDialog {
private String backGround;
private String shape;
private String title;
/**
*
* @Title: init
* @Description: 初始化
* @param params
*/
public void init(AlertDialogBuilder.AlertDialogParams params) {
this.backGround = params.backGround;
this.shape = params.shape;
this.title = params.title;
}
/**
* 複寫
*/
@Override
public String toString() {
return "AlertDialog[backGround=" + backGround + ",shape=" + shape
+ ",title=" + title + "]";
}
public AlertDialog() {
}
public String getBackGround() {
return backGround;
}
public void setBackGround(String backGround) {
this.backGround = backGround;
}
public String getShape() {
return shape;
}
public void setShape(String shape) {
this.shape = shape;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
測試
package demo11;
/**
*
* @ClassName: ClientTest
* @Description:測試
* @author cheng
* @date 2017-8-15 下午02:21:52
*/
public class ClientTest {
public static void main(String[] args) {
AlertDialog alertDialog = new AlertDialogBuilder()
.createBackGround("黑色")
.createShape("圓形")
.createTitle("确認登入")
.build();
System.out.println(alertDialog);
}
}
運作結果
好處
使用建造者模式可以使用戶端不必知道産品内部組成的細節。
具體的建造者類之間是互相獨立的,對系統的擴充非常有利。
由于具體的建造者是獨立的,是以可以對建造過程逐漸細化,而不對其他的子產品産生任何影響。
使用場合
建立一些複雜的對象時,這些對象的内部組成構件間的建造順序是穩定的,但是對象的内部組成構件面臨着複雜的變化
要建立的複雜對象的算法,獨立于該對象的組成部分,也獨立于組成部分的裝配方法時。