Builder模式是一步一步創建複雜對象的創建型模式。允許用戶在不知道內部構建細節的情況下,可以更精細的控制構造流程。該模式是為了將構建過程和表示分開,使構建過程和部件都可以自由擴展,兩者的耦合度也降到最低。
定義
將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
使用場景
相同的方法,不同的執行順序,產生不同的結果。
多個部件或零件都可以裝配到一個對象中,但產生的運行結果又不相同時。
產品類非常複雜,或者構建部件的順序不同產生了不同的作用。
當初始化一個對象特別複雜時,如參數特別多且很多參數都有默認值的時
UML類圖
Product 產品的抽象類
Builder 抽象的Builder類,規範產品的組建,一般由子類實現具體的構建過程
角色介紹:
ConcreteBuilder 具體的Builder類
Director 統一組裝類,導演類
簡單實現
書中以計算機舉了個例子
先創建計算機的抽象類
public abstract class Computer { /**
創建計算機的一個實現類 蘋果計算機
public class Macbook extends Computer {
創建builder的抽象類,規範產品的組建
public abstract class Builder { public abstract Builder buildBoard(String board); public abstract Builder buildDisplay(String display); public abstract Builder buildOS(); public abstract Computer create();
創建具體的Builder類,實現蘋果計算機的組裝
public class MacbookBuilder extends Builder { private Computer mComputer = new Macbook();//這裡的方法返回builder本身,可以鏈式調用
//調用這個方法生成最終的產品
@Override
導演類
public class Director {
-使用示例
public class MainM { public static void main(String[] args) {
-打印結果
Computer{mBoard='huashuo', mDisplay='sanxing', mOS='macOS'}
Android源碼中的Builder模式實現
我們在構建對話框的時候通常都是以下的用法:
private void showDialog(final Context context) {
可以看出AlertDialog就是通過AlertDialog.Builder來構建的。
AlertDialog源碼:
看著源碼來分析
創建AlertDialog
public class AlertDialog extends Dialog implements DialogInterface { //留意這個變量
在源碼中可以看出,我們通過builder的各種setxxx方法設置一些屬性的時候,builder吧這些設置都存在一個變量P中,這個P在Builder創建時在構造方法中初始化,類型是AlertController.AlertParams,是AlertController的內部類。
然後在Builder的create方法中,new一個新的AlertDialog,並在AlertDialog的構造方法中初始化了AlertDialog的變量mAlert,類型是AlertController。
調用P.apply(mAlert)方法把P中保存的參數傳遞給AlertDialog的變量mAlert。最後返回這個生成的AlertDialog。
看一下這個方法:
package com.android.internal.app;public class AlertController { public static class AlertParams { public void apply(AlertController dialog) {//基本上所有的方法都是把自己的參數設置給傳進來的dialog。
顯示AlertDialog
在上面的使用例子中可以看出,獲取到Dialog後,直接調用alertDialog.show()就能顯示AlertDialog了。
package android.app;public class Dialog implements DialogInterface, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, Window.OnWindowDismissedCallback { public void show() {//如果已經顯示,就直接return
簡單分析一下這個方法的主要流程就是:
(1)先確認AlertDialog的onCreate方法是否執行,如果沒有執行就調用dispatchOnCreate(null)方法來調用AlertDialog的onCreate方法。
(2)調用Dialog的onStart()方法。
(3)將設置好的DecorView添加到WindowManager中。
在AlertDialog的onCreate方法中只有兩行代碼:
@Override
mAlert就是AlertDialog的AlertController類型的變量。
package com.android.internal.app;public class AlertController { public void installContent() {//獲取相應的對話框內容的佈局
分析LayoutInflater時就知道,Activity的setContentView最後也是調用了Window.setContentView這個方法。所以這個方法裡主要就是給對話框設置佈局。
private int selectContentView() { if (mButtonPanelSideLayout == 0) { return mAlertDialogLayout;
看到通過selectContentView()獲得的佈局是mAlertDialogLayout,那麼這個佈局是什麼時候初始化的呢?
在AlertController的構造方法中可以看見:
protected AlertController(Context context, DialogInterface di, Window window) { mContext = context; mDialogInterface = di; mWindow = window; mHandler = new ButtonHandler(di);
好,來看一下佈局文件,也就是alert_dialog.xml
默認的佈局是這樣的,本來文件中是空白的,為了能看出來,我給佈局設置了一些值和背景色:
系統默認的dialog佈局
源代碼貼出來,可以自己試試:
alert_dialog.xml<LinearLayout
回到AlertController的installContent()方法中,看下一行代碼setupView();
private void setupView() {//獲取alert_dialog.xml中的佈局
所以setupView的流程就是:
(1)初始化AlertDialog佈局中的各個部分
(2)佈局全部設置完畢後,又通過Window對象關聯到DecorView。並將DecorView添加到用戶窗口上顯示出來。
總結
優點
良好的封裝性,使用Builder模式可以使客戶端不必知道產品的內部組成的細節
builder獨立,容易擴展
缺點
會產生多餘的Builder對象以及Director對象(用的不多),消耗內存