一、定義
講一個(gè)復(fù)雜對(duì)象的構(gòu)建與他的表示分離,使用同樣的構(gòu)建過(guò)程實(shí)現(xiàn)不同的表示;
- 分類:創(chuàng)建型模式
二、使用場(chǎng)景
相同的方法,不同的執(zhí)行順序,產(chǎn)生不一樣的事件結(jié)果;
將多個(gè)零件(部分),通過(guò)不同的執(zhí)行順序,而產(chǎn)生不同表示結(jié)果;
-
產(chǎn)品類非常復(fù)雜,如:參數(shù)太多,很多參數(shù)都具有默認(rèn)值,或通過(guò)不同的順序,獲取不同的表示結(jié)果;
核心:不同的方法順序,獲取不同的表示結(jié)果;
三、UML類圖
標(biāo)準(zhǔn)Builder模式

標(biāo)準(zhǔn)Builder模式
簡(jiǎn)單Builder模式

簡(jiǎn)單Builder模式
Builder的變種

Builder的變種
備注:Bean 存儲(chǔ)數(shù)據(jù)的實(shí)體,在實(shí)體內(nèi)部實(shí)現(xiàn)Builder;
角色介紹:
-
Product 產(chǎn)品(抽象)類
可以是具體的產(chǎn)品,也可以是產(chǎn)品的抽象類,對(duì)產(chǎn)品的相關(guān)進(jìn)行設(shè)計(jì)或?qū)崿F(xiàn); -
Buider抽象類
用于編寫B(tài)uilder的抽象,規(guī)范產(chǎn)品的組建; -
ConcreteBuilder實(shí)現(xiàn)類
實(shí)現(xiàn)對(duì)產(chǎn)品的具體的操作流程; -
Director(主管類)
實(shí)現(xiàn)Builder的統(tǒng)一組裝過(guò)程;
備注:一般實(shí)現(xiàn)過(guò)程中,經(jīng)常會(huì)將主管類省略,直接使用Builder對(duì)產(chǎn)品進(jìn)行操作,它會(huì)返回this對(duì)象,以此來(lái)實(shí)現(xiàn)Builder的鏈?zhǔn)秸{(diào)用,這種模式,我管他叫簡(jiǎn)單Builder模式;該方法,結(jié)構(gòu)更加簡(jiǎn)單,對(duì)比標(biāo)準(zhǔn)結(jié)構(gòu)也沒(méi)有明顯的缺點(diǎn),推薦使用這種模式;
四、代碼實(shí)現(xiàn)
代碼以顧客在蘋果專賣店挑選手機(jī)為例。顧客挑選手機(jī)時(shí),會(huì)根據(jù)系統(tǒng)、cpu、屏幕等等參數(shù)進(jìn)行選擇手機(jī);
1. 標(biāo)準(zhǔn)Builder模式
/**
* Created by zhangxuehui on 2017/6/18.
* 蘋果專賣店
*/
public class BuilderAppleShop {
public static void main(String[] args) {
Builder builder = new AppleBuilder();
Director director = new Director(builder);
director.buyMoble("A9", "4.7");
System.out.println("用戶購(gòu)買的第一部手機(jī)是:" + buildr.create().toString());
director.buyMoble("ios 11", "A10", "5.5");
System.out.println("用戶購(gòu)買的第二部手機(jī)是:" + buildr.create().toString());
}
/**
* 手機(jī)配置抽象類,標(biāo)準(zhǔn)化手機(jī)的核心參數(shù)
*/
static abstract class Mobile {
protected String logo;//品牌
protected String cpu;//cpu處理器
protected String os;//系統(tǒng)
protected String screenSize;//屏幕尺寸
abstract void logo();//蘋果專賣店只有蘋果的產(chǎn)品,所以logo相當(dāng)于手機(jī)標(biāo)志,必須由具體的手機(jī)類實(shí)現(xiàn);
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public abstract void os();//手機(jī)一定會(huì)有系統(tǒng),需要有一個(gè)默認(rèn)的系統(tǒng),可以有用戶動(dòng)態(tài)設(shè)置
public void setOs(String os) { //顧客可以選擇不同版本的系統(tǒng),
this.os = os;
}
public String getScreenSize() {
return screenSize;
}
public void setScreenSize(String screenSize) {
this.screenSize = screenSize;
}
@Override
public String toString() {
return "Mobile{" +
"logo='" + logo + '\'' +
", cpu='" + cpu + '\'' +
", os='" + os + '\'' +
", screenSize='" + screenSize + '\'' +
'}';
}
}
/**
* 蘋果手機(jī)類--產(chǎn)品的具體實(shí)現(xiàn)類
*/
static class AppleMobile extends Mobile {
@Override
void logo() {
logo = "apple";
}
@Override
public void os() {
os = "ios 10";
}
}
/**
* 建造者的抽象類,規(guī)范操作以及流程
*/
static abstract class Builder {
abstract void builderLogo();
abstract void builderOs();
abstract void builderOs(String os);
abstract void builderScreenSize(String size);
abstract void builderCpu(String cpu);
abstract Mobile create();
}
/**
* 建造者的具體實(shí)現(xiàn)類
*/
public static class AppleBuilder extends Builder {
Mobile mobile = new AppleMobile();
@Override
void builderLogo() {
mobile.logo();
}
@Override
void builderOs() {
mobile.os();
}
@Override
void builderOs(String os) {
mobile.setOs(os);
}
@Override
void builderScreenSize(String size) {
mobile.setScreenSize(size);
}
@Override
void builderCpu(String cpu) {
mobile.setCpu(cpu);
}
@Override
Mobile create() {
return mobile;
}
}
/**
* 主管類,對(duì)Builder進(jìn)行統(tǒng)一操作
*/
public static class Director {
Builder mBuildr = null;
public Director(Builder mBuildr) {
this.mBuildr = mBuildr;
mBuildr.builderLogo();
}
//購(gòu)買自選系統(tǒng)版本的手機(jī)
public void buyMoble(String os, String cpu, String size) {
mBuildr.builderOs(os);
mBuildr.builderCpu(cpu);
mBuildr.builderScreenSize(size);
}
//購(gòu)買官方默認(rèn)系統(tǒng)的手機(jī)
public void buyMoble(String cpu, String size) {
mBuildr.builderCpu(cpu);
mBuildr.builderScreenSize(size);
mBuildr.builderOs();
}
}
}
備注:
- 引用產(chǎn)品的具體實(shí)現(xiàn)時(shí),實(shí)例的類型應(yīng)為其抽象類;
- Builder類中,一定要實(shí)現(xiàn)create()方法;
- 要對(duì)產(chǎn)品層、Builder層、Directer層,進(jìn)行合理劃分,Builder僅處理產(chǎn)品,Directer僅處理Builder;不可以出現(xiàn),Directer處理產(chǎn)品類的情況;
輸出結(jié)果

輸出結(jié)果
2. 簡(jiǎn)單Builder模式 (進(jìn)化版)
/**
* Created by zhangxuehui on 2017/6/18.
* 蘋果專賣店
*/
public class SimpleBuilderAppleShop {
public static void main(String[] args) {
Builder builder = new AppleBuilder();
Mobile mobile1 = builder.builderScreenSize("5.5").builderCpu("A10").create();
System.out.println("用戶購(gòu)買的第一部手機(jī)是:" + mobile1.toString());
Mobile mobile2 = builder.builderScreenSize("4.7").builderCpu("A9").builderOs("ios 7").create();
System.out.println("用戶購(gòu)買的第二部手機(jī)是:" + mobile2.toString());
}
/**
* 手機(jī)配置抽象類,標(biāo)準(zhǔn)化手機(jī)的核心參數(shù)
*/
static abstract class Mobile {
protected String logo;//品牌
protected String cpu;//cpu處理器
protected String os;//系統(tǒng)
protected String screenSize;//屏幕尺寸
abstract void logo();//蘋果專賣店只有蘋果的產(chǎn)品,所以logo相當(dāng)于手機(jī)標(biāo)志,必須由具體的手機(jī)類實(shí)現(xiàn);
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public abstract void os();//手機(jī)一定會(huì)有系統(tǒng),需要有一個(gè)默認(rèn)的系統(tǒng),可以有用戶動(dòng)態(tài)設(shè)置
public void setOs(String os) { //顧客可以選擇不同版本的系統(tǒng),
this.os = os;
}
public String getScreenSize() {
return screenSize;
}
public void setScreenSize(String screenSize) {
this.screenSize = screenSize;
}
@Override
public String toString() {
return "Mobile{" +
"logo='" + logo + '\'' +
", cpu='" + cpu + '\'' +
", os='" + os + '\'' +
", screenSize='" + screenSize + '\'' +
'}';
}
}
/**
* 蘋果手機(jī)類--產(chǎn)品的具體實(shí)現(xiàn)類
*/
static class AppleMobile extends Mobile {
@Override
void logo() {
logo = "apple";
}
@Override
public void os() {
os = "ios 10";
}
}
/**
* 建造者的抽象類,規(guī)范操作以及流程
*/
static abstract class Builder {
abstract Builder builderLogo();
abstract Builder builderOs();
abstract Builder builderOs(String os);
abstract Builder builderScreenSize(String size);
abstract Builder builderCpu(String cpu);
abstract Mobile create();
}
/**
* 建造者的具體實(shí)現(xiàn)類
*/
public static class AppleBuilder extends Builder {
Mobile mobile = new AppleMobile();
//在構(gòu)造方法中初始化默認(rèn)值
public AppleBuilder() {
builderLogo();
builderOs();
}
@Override
Builder builderLogo() {
mobile.logo();
return this;//除去create()全部返回this,方便鏈?zhǔn)秸{(diào)用。
}
@Override
Builder builderOs() {
mobile.os();
return this;
}
@Override
Builder builderOs(String os) {
mobile.setOs(os);
return this;
}
@Override
Builder builderScreenSize(String size) {
mobile.setScreenSize(size);
return this;
}
@Override
Builder builderCpu(String cpu) {
mobile.setCpu(cpu);
return this;
}
@Override
Mobile create() {
return mobile;//將設(shè)置好的對(duì)象返回;
}
}
}
備注:
- 與標(biāo)準(zhǔn)模式的主要區(qū)別,在于完全去除了Direct類,用戶直接操作Builder;
- Builder類中,除create()其他全部返回this,便于鏈?zhǔn)秸{(diào)用;
- 用戶直接獲取最終配置好的產(chǎn)品類;
輸出結(jié)果

輸出結(jié)果
3. Builder的變種
public class User {
private final String Name;//姓名 必選
private final int idCode;//身份證 必選
private final int age;//年齡 可選
private final String like;//愛(ài)好 可選
private final String language;//語(yǔ)言 可選
private final String address;//地址 可選
//傳人Builder對(duì)實(shí)體設(shè)置參數(shù)
public User(Builder builder) {
this.Name = builder.name;
this.idCode = builder.idCode;
this.age = builder.age;
this.like = builder.like;
this.language = builder.language;
this.address = builder.address;
}
@Override
public String toString() {
return "User{" +
"Name='" + Name + '\'' +
", idCode=" + idCode +
", age=" + age +
", like='" + like + '\'' +
", language='" + language + '\'' +
", address='" + address + '\'' +
'}';
}
/**
* 實(shí)現(xiàn)builder內(nèi)部類,用于配置實(shí)體的參數(shù)
*/
public static class Builder {
//拷貝一份與user實(shí)體相同的參數(shù),并且不設(shè)置為final
private String name;//姓名 必選
private int idCode;//身份證 必選
private int age;//年齡 可選
private String like;//愛(ài)好 可選
private String language;//語(yǔ)言 可選
private String address;//地址 可選
//對(duì)必選的參數(shù)在構(gòu)造方法中進(jìn)行設(shè)置
public Builder(String name, int idCode) {
this.name = name;
this.idCode = idCode;
}
//參數(shù)設(shè)置時(shí),應(yīng)該返回當(dāng)前類對(duì)象,用于鏈?zhǔn)秸{(diào)用
public Builder setAge(int age) {
this.age = age;
return this;
}
public Builder setLike(String like) {
this.like = like;
return this;
}
public Builder setLanguage(String language) {
this.language = language;
return this;
}
public Builder setAddress(String address) {
this.address = address;
return this;
}
//配置完參數(shù)后,將builder傳遞給User,完成創(chuàng)建。
protected User create() {
return new User(this);
}
}
}
使用
public static void main(String[] args) {
User u = new User.Builder("張山",123)
.setAddress("北京市")
.setAge(18)
.setLanguage("中文")
.setLike("游泳")
.create();
System.out.println(u.toString());
}
備注
1.該模式適用于,需要的初始化操作,或構(gòu)造方法的時(shí)候需要傳人大量的參數(shù);
五、android源碼中的實(shí)現(xiàn)(Dialog)
public class AlertDialog extends AppCompatDialog implements DialogInterface {
final AlertController mAlert;//Dialog的控制類,所有邏輯都在其內(nèi)部實(shí)現(xiàn)
/********無(wú)關(guān)代碼忽略********/
/**
* Construct an AlertDialog that uses an explicit theme. The actual style
* that an AlertDialog uses is a private implementation, however you can
* here supply either the name of an attribute in the theme from which
* to get the dialog's style (such as {@link R.attr#alertDialogTheme}.
* 核心構(gòu)造方法,用于綁定AlertController
*/
protected AlertDialog(@NonNull Context context, @StyleRes int themeResId) {
super(context, resolveDialogTheme(context, themeResId));
mAlert = new AlertController(getContext(), this, getWindow());
}
//對(duì)外開(kāi)放的按鈕,
public Button getButton(int whichButton) {
return mAlert.getButton(whichButton);
}
/*這一部分,是對(duì)外開(kāi)放的view操作,如設(shè)置按鈕、圖標(biāo)、文字等*/
@Override
protected void onCreate(Bundle savedInstanceState) {//與生命周期綁定
super.onCreate(savedInstanceState);
mAlert.installContent();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {//對(duì)按鍵進(jìn)行處理
if (mAlert.onKeyDown(keyCode, event)) {
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {//對(duì)按鍵進(jìn)行處理
if (mAlert.onKeyUp(keyCode, event)) {
return true;
}
return super.onKeyUp(keyCode, event);
}
/**
* 重點(diǎn)來(lái)啦,AlertDialog的builder類
**/
public static class Builder {
//核心參數(shù),在Builder中配置的參數(shù)都會(huì)賦值給它,再由它轉(zhuǎn)交給AlertController,最后由AlertDialog,直接獲取Controller;
private final AlertController.AlertParams P;
private final int mTheme;
/**
* 構(gòu)造,必填參數(shù)context,略
*/
public Builder(@NonNull Context context) {
this(context, resolveDialogTheme(context, 0));
}
/**
* 構(gòu)造,必填參數(shù)context和Theme,略
*/
public Builder(@NonNull Context context, @StyleRes int themeResId) {
P = new AlertController.AlertParams(new ContextThemeWrapper(
context, resolveDialogTheme(context, themeResId)));
mTheme = themeResId;
}
@NonNull
public Context getContext() {
return P.mContext;
}
/**
* Set the title using the given resource id.
*
* @return This Builder object to allow for chaining of calls to set methods
*/
public Builder setTitle(@StringRes int titleId) {
P.mTitle = P.mContext.getText(titleId);
return this;
}
/**
* 這一部分為,配置標(biāo)題、圖片、文字、listview、監(jiān)聽(tīng)事件等,所有的配置參數(shù)都會(huì)通過(guò)P配置,如:P.mTitle = P.mContext.getText(titleId),其他方法基本與上邊相同,不解釋;
*/
/**
* 重點(diǎn)看看它的create實(shí)現(xiàn)。
* 1.初始化AlertDialog;
* 2.將AlertController.AlertParams中的參數(shù)配置給AlertDialog。
* 3.配置監(jiān)聽(tīng)事件,并返回AlertDialog對(duì)象
*/
public AlertDialog create() {
// We can't use Dialog's 3-arg constructor with the createThemeContextWrapper param,
// so we always have to re-set the theme
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme);
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
if (P.mCancelable) {
dialog.setCanceledOnTouchOutside(true);
}
dialog.setOnCancelListener(P.mOnCancelListener);
dialog.setOnDismissListener(P.mOnDismissListener);
if (P.mOnKeyListener != null) {
dialog.setOnKeyListener(P.mOnKeyListener);
}
return dialog;
}
/**
* 用于顯示dialog
*/
public AlertDialog show() {
final AlertDialog dialog = create();
dialog.show();
return dialog;
}
}
}
總結(jié)
源碼中的Builder使用的很有趣,他沒(méi)有像我們常見(jiàn)的講參數(shù)直接配置給對(duì)象,而是通過(guò)一個(gè)Controller類實(shí)現(xiàn)邏輯,Controller的內(nèi)部類AlertParams配置它的參數(shù),而不論Builder類還是AlertDialog類都只是一個(gè)入口。當(dāng)然一切都從Builder開(kāi)始。