設計模式之二:Builder模式
目錄介紹php
0.本人寫的綜合案例git
1.1 定義: 將一個複雜對象的構建與它的表示分離,使得一樣的構建過程能夠建立不一樣的展現。
1.2 Builder模式屬於建立型,一步一步將一個複雜對象建立出來,容許用戶在不知道內部構建細節的狀況下,能夠更精細地控制對象的構造流程。github
相同方法,不一樣執行順序,產生不一樣事件結果
初始化對象特別複雜,參數衆多,且不少參數都具備默認值時設計模式
3.1 Builder模式UML圖(摘自網絡)安全
3.2 在《Android源碼設計模式》這本書上,介紹經典Builder模式中,包括網絡
3.3 Product角色app
//設置抽象類 public abstract class BuilderUser { protected String name; protected String cardID; protected int age; protected String address; public BuilderUser() {} //設置名字 public void setName(String name) { this.name = name; } //抽象方法 public abstract void setCardID(); //設置年齡 public void setAge(int age) { this.age = age; } //設置地址 public void setAddress(String address) { this.address = address; } @Override public String toString() { return "BuilderUser{" + "name='" + name + ''' + ", cardID='" + cardID + ''' + ", age=" + age + ", address='" + address + ''' + '}'; } } /** * 具體的Product角色 UserCard */ public class UserCard extends BuilderUser { public UserCard() {} @Override public void setCardID() { cardID="10086"; //設置默認ID } }
3.4 Builder : 抽象Builder類,規範產品組建,通常是由子類實現具體的組建過程ide
/** * 抽象Builder類 */ public abstract class Builder { public abstract void buildName(String name); public abstract void buildCardID(); public abstract void buildAge(int age); public abstract void buildAddress(String address); public abstract BuilderUser create(); }
3.5 ConcreteBuilder : 具體的Builder類函數
/** * 具體的Builder類 */ public class AccountBuilder extends Builder{ private BuilderUser user = new UserCard(); @Override public void buildName(String name) { user.setName(name); } @Override public void buildCardID() { user.setCardID(); } @Override public void buildAge(int age) { user.setAge(age); } @Override public void buildAddress(String address) { user.setAddress(address); } @Override public BuilderUser create() { return user; } }
3.6 Director : 統一組裝過程佈局
/** * Director角色,負責構造User */ public class Director { Builder mBuilder =null; public Director(Builder builder){ this.mBuilder =builder; } public void construct(String name,int age,String address){ mBuilder.buildName(name); mBuilder.buildCardID(); mBuilder.buildAge(age); mBuilder.buildAddress(address); } }
4.1 實際開發中,有時會遇到複雜的對象的代碼,好比
public class BuilderDemo { private final String name; //必選 private final String cardID; //必選 private final int age; //可選 private final String address; //可選 private final String phone; //可選 }
4.2 經過構造函數的參數形式去寫一個實現類,或者經過set,get去實現
BuilderDemo(String name); BuilderDemo(String name, String cardID); BuilderDemo(String name, String cardID,int age); BuilderDemo(String name, String cardID,int age, String address); BuilderDemo(String name, String cardID,int age, String address,String phone);
4.3 分析
4.4 將上面例子改爲builder模式以下所示
public class BuilderDemo { private final String name; //必選 private final String cardID; //必選 private final int age; //可選 private final String address; //可選 private final String phone; //可選 public BuilderDemo(UserBuilder userBuilder){ this.name=userBuilder.name; this.cardID=userBuilder.cardID; this.age=userBuilder.age; this.address=userBuilder.address; this.phone=userBuilder.phone; } public static class UserBuilder{ private final String name; private final String cardID; private int age; private String address; private String phone; public BuilderDemo build(){ return new BuilderDemo(this); } public UserBuilder(String name,String cardID){ this.name=name; this.cardID=cardID; } public UserBuilder age(int age){ this.age=age; return this; } public UserBuilder address(String address){ this.address=address; return this; } public UserBuilder phone(String phone){ this.phone=phone; return this; } } }
4.5 最後運用,代碼以下
new BuilderDemo.UserBuilder("yc","10086") .age(24) .address("beijing") .phone("13667225184") .build();
4.6 關於線程安全問題
// 線程安全 public BuilderDemo build(){ BuilderDemo builderDemo = new BuilderDemo(this); if(builderDemo.age > 100){ throw new IllegalStateException("Age out of range"); } return builderDemo; } // 線程不安全,不要這樣寫 public BuilderDemo build(){ if(age > 100){ throw new IllegalStateException("Age out of range"); } return new BuilderDemo(this); }
5.1 首先看看AlertDialog.Builder源代碼,只是摘自部分代碼
public class AlertDialog extends AppCompatDialog implements DialogInterface { //接收builder成員變量p中各個參數 final AlertController mAlert; //下面是三個構造函數 protected AlertDialog(@NonNull Context context) { this(context, 0); } protected AlertDialog(@NonNull Context context, @StyleRes int themeResId) { super(context, resolveDialogTheme(context, themeResId)); mAlert = new AlertController(getContext(), this, getWindow()); } protected AlertDialog(@NonNull Context context, boolean cancelable, @Nullable OnCancelListener cancelListener) { this(context, 0); setCancelable(cancelable); setOnCancelListener(cancelListener); } //事件上這裏調用了是mAlert的setView方法 public void setView(View view) { mAlert.setView(view); } public void setView(View view, int viewSpacingLeft, int viewSpacingTop, int viewSpacingRight, int viewSpacingBottom) { mAlert.setView(view, viewSpacingLeft, viewSpacingTop, viewSpacingRight, viewSpacingBottom); } public static class Builder { //這個裏面存放不少參數 private final AlertController.AlertParams P; //這個是new AlertDialog.Builder(context,R.style.AppTheme)調用的方法 public Builder(@NonNull Context context, @StyleRes int themeResId) { P = new AlertController.AlertParams(new ContextThemeWrapper( context, resolveDialogTheme(context, themeResId))); mTheme = themeResId; } //這部分代碼省略不少,主要是set設置各類參數 public Builder setTitle(@Nullable CharSequence title) { P.mTitle = title; return this; } //這部分代碼省略不少,主要是set設置各類參數 public Builder setView(int layoutResId) { P.mView = null; P.mViewLayoutResId = layoutResId; P.mViewSpacingSpecified = false; return this; } //構建dialog,傳遞參數 public AlertDialog create() { 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; } } }
5.2 接下來看看build源代碼
public AlertDialog create() { //建立 final AlertDialog dialog = new AlertDialog(P.mContext, mTheme); //這一步很重要,下面會單獨分析 P.apply(dialog.mAlert); //設置是否能夠取消,默認是true dialog.setCancelable(P.mCancelable); if (P.mCancelable) { dialog.setCanceledOnTouchOutside(true); } //設置取消監聽 dialog.setOnCancelListener(P.mOnCancelListener); //設置dialog關閉後監聽 dialog.setOnDismissListener(P.mOnDismissListener); //設置返回鍵監聽 if (P.mOnKeyListener != null) { dialog.setOnKeyListener(P.mOnKeyListener); } //返回對象,建立成功 return dialog; }
5.3 接下來看看show的代碼
public void show() { //若是彈窗已經show出來了 if (mShowing) { //若是頂級view存在則設置窗口window,並顯示頂級View if (mDecor != null) { if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) { mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR); } mDecor.setVisibility(View.VISIBLE); } return; } mCanceled = false; //若是窗口還未被建立 if (!mCreated) { dispatchOnCreate(null); } //得到Windowd的頂級View,並將其添加到對應的WindowManager中,而後發送show的消息 onStart(); //獲取DecorView mDecor = mWindow.getDecorView(); if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) { final ApplicationInfo info = mContext.getApplicationInfo(); mWindow.setDefaultIcon(info.icon); mWindow.setDefaultLogo(info.logo); mActionBar = new WindowDecorActionBar(this); } //獲取佈局參數 WindowManager.LayoutParams l = mWindow.getAttributes(); if ((l.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) { WindowManager.LayoutParams nl = new WindowManager.LayoutParams(); nl.copyFrom(l); nl.softInputMode |= WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; l = nl; } try { //將mDecor添加到WindowManager中 mWindowManager.addView(mDecor, l); mShowing = true; //發送一個顯示Dialog消息 sendShowMessage(); } finally { } }
(2)而後接着調用onStart函數
(3)最後將Dialog的mDecor添加到WindowManager中(有點不明白這裏,爲何要獲取到最頂部的佈局)
5.4 爲何AlertDialog要使用builder模式呢?
AlertDialog(String title); AlertDialog(String message) AlertDialog(int resId) AlertDialog(int resId, String title, String message); AlterDialog(int resId, String title, String message, String PositiveButtonString, OnClickListener listener); AlterDialog(int resId, String title, String message, String PositiveButtonString, OnClickListener listener); AlterDialog(int resId, String title, String message, String NegativeButtonString, OnClickListener listener); AlterDialog(int resId, String title, String message, String PositiveButtonString, OnClickListener listener, String NegativeButtonString, OnClickListener listener); ....
6.1 Builder模式有幾個好處:
6.2 固然Builder模式也有缺點:
7.1 參考案例