JAVA設(shè)計(jì)模式【創(chuàng)建型模式】之【Builder】

前言

其他創(chuàng)建型模式:

今天來(lái)介紹創(chuàng)建型模式之Builder(生成器)洗搂。Builder模式在Android開發(fā)中我們遇到很多燕垃,無(wú)論是平時(shí)的開發(fā),還是在閱讀Android源碼的過程都會(huì)遇到躲胳。例如Android源碼中:

  • app核心層: Notification.Builder(android.app)
  • 圖形繪制層:TypeFace.Builder(android.graphics)
  • 底層硬件層:BluetoothDeviceFilter.Builder(android.companion)
  • 網(wǎng)絡(luò)層:Uri.Builder(android.net)

可以發(fā)現(xiàn)糠排,在Android的源碼框架中灶轰,Builder模式的運(yùn)用真的是非常普遍冤荆。

大家可以通過快捷鍵在Android源碼當(dāng)中搜索Builder即可辽话。最常見的就是AlertDialog.Builder對(duì)象扔役,如下圖所示:

Builder

可以看到這么多方法才使得我們?cè)赾oding時(shí)去create一個(gè)Dialog對(duì)象的時(shí)候才能隨心所欲帆喇,Android中創(chuàng)建Dialog的這種方式,充分的體現(xiàn)了Builder模式的強(qiáng)大和靈活亿胸。

接下來(lái)我們來(lái)具體學(xué)習(xí)Builder模式:

1. 意圖

將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離坯钦,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。

2. 適用性

  • 當(dāng)創(chuàng)建復(fù)雜對(duì)象的算法應(yīng)該獨(dú)立于該對(duì)象的組成部分以及它們的裝配方式時(shí)侈玄。
  • 當(dāng)構(gòu)造過程必須允許被構(gòu)造的對(duì)象有不同的表示時(shí)婉刀。

3. 參與者

  • Builder —— 為創(chuàng)建一個(gè)Product對(duì)象的各個(gè)部件指定抽象接口。
  • ConcreteBuilder
    —實(shí)現(xiàn)Builder的接口以構(gòu)造和裝配該產(chǎn)品的各個(gè)部件序仙。
    — 定義并明確它所創(chuàng)建的表示突颊。
    — 提供一個(gè)檢索產(chǎn)品的接口。
  • Director —— 構(gòu)造一個(gè)使用Builder接口的對(duì)象潘悼。
  • Product
    — 表示被構(gòu)造的復(fù)雜對(duì)象律秃。ConcreteBuilder創(chuàng)建該產(chǎn)品的內(nèi)部表示并定義它的裝配過程。
    — 包含定義組成部件的類治唤,包含將這些部件裝配成最終產(chǎn)品的接口棒动。

4. 效果

1)它使你可以改變一個(gè)產(chǎn)品的內(nèi)部表示時(shí)
2)它將構(gòu)造代碼和表示代碼分開
3)它使你對(duì)構(gòu)造過程進(jìn)行更精細(xì)的控制

5. 實(shí)例

我們還是以汽車為例子,


汽車構(gòu)造圖

汽車一般一共由五大部分組成:

  • 發(fā)動(dòng)機(jī)(Engine)
  • 傳動(dòng)系統(tǒng)(Power)
  • 車身(body)
  • 轉(zhuǎn)向(Steering)
  • 懸掛(Suspension)

那么就可以抽象出對(duì)應(yīng)的Builder接口:
CarBuilder.java

  public interface CarBuilder {
    /**
     * 構(gòu)建發(fā)動(dòng)機(jī)
     */
    void buildEngine();
    /**
     * 構(gòu)建傳動(dòng)系統(tǒng)
     */
    void buildPower();
    /**
     * 構(gòu)建車身
     */
    void buildBody();
    /**
     * 構(gòu)建轉(zhuǎn)向
     */
    void buildSteering();
    /**
     * 構(gòu)建懸掛
     */
    void buildSuspension();

    Car buildCar();

那么對(duì)應(yīng)的參與者Product就是汽車本身宾添,這里我們以寶馬和奧迪來(lái)進(jìn)行舉例:

Car汽車類圖

對(duì)應(yīng)的ConcreteBuilder 就是AudiBuilder和BmwBuilder船惨,如下圖
image.png

然后需要一個(gè)Director的角色來(lái)指導(dǎo)不同的Car的構(gòu)建:

CarDirector.java

public class CarDirector {
    public Car buildCar(CarBuilder carBuilder) {
        carBuilder.buildBody();
        carBuilder.buildEngine();
        carBuilder.buildPower();
        carBuilder.buildSteering();
        carBuilder.buildSuspension();
        return carBuilder.buildCar();
    }
}

最后我們來(lái)測(cè)試一下:

private static void testBuilder() {
        CarDirector carDirector = new CarDirector();
        //構(gòu)建奧迪車
        final Car audiCar = carDirector.buildCar(new AudiCarBuilder());
        System.out.println(audiCar.toString());
        //構(gòu)建寶馬車
        final Car bmwCar = carDirector.buildCar(new BmwCarBuilder());
        System.out.println(bmwCar.toString());
 }

測(cè)試結(jié)果下圖所示:


image.png

實(shí)踐完汽車的這個(gè)簡(jiǎn)單的實(shí)例,我們?cè)賮?lái)看一下Android中經(jīng)典的Builder模式之AlertDialog.Builder:

//很經(jīng)典的鏈?zhǔn)秸{(diào)用有木有(一氣呵成)
AlertDialog dialog = new AlertDialog.Builder(this)
                .setTitle("title")
                .setMessage("message")
                .create();
            dialog.show();

通過閱讀AlertDialog.Builder源碼缕陕,可以看出Builder類是屬于AlertDialog類的一個(gè)靜態(tài)內(nèi)部類粱锐,由源碼過多,我們只分析部分構(gòu)建過程:

public class AlertDialog extends Dialog implements DialogInterface {

    //.....此處省略若干行代碼

    public static class Builder {
        private final AlertController.AlertParams P;

        public Builder(Context context) {
            this(context, resolveDialogTheme(context, ResourceId.ID_NULL));
        }

        public Builder setTitle(@StringRes int titleId) {
            P.mTitle = P.mContext.getText(titleId);
            return this;
        }


        public Builder setMessage(CharSequence message) {
            P.mMessage = message;
            return this;
        }

        public AlertDialog create() {
            //構(gòu)建一個(gè)新AlertDialog對(duì)象榄檬,并通過AlertController.AlertParams配置Dialog
            final AlertDialog dialog = new AlertDialog(P.mContext, 0, false);
            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;
        }

        public AlertDialog show() {
            final AlertDialog dialog = create();
            dialog.show();
            return dialog;
        }
        
        //.....此處省略若干行代碼
    }
}

和構(gòu)造汽車的Builder模式相比較卜范,AlertDialog.Builder缺少了Director角色,但是這并不影響B(tài)uilder模式的效果鹿榜,其精髓之處就是體現(xiàn)在程序員一步步構(gòu)建Dialog對(duì)象的時(shí)候,其實(shí)也可以把具體使用Dialog情景或者方法體看成是一個(gè)虛的Director锦爵。

第三方庫(kù)中Builder的使用

另外Builder的構(gòu)建經(jīng)常在靜態(tài)工廠的構(gòu)建對(duì)象或者作為第三方庫(kù)使用的時(shí)候出現(xiàn)舱殿,比如知乎開源的一個(gè)強(qiáng)大圖片選擇器Matisse


在使用Matisse的時(shí)候就是經(jīng)典的鏈?zhǔn)秸{(diào)用+Builder模式,這里Matisse本身其實(shí)就是Builder !!!

Matisse.from(MainActivity.this)
        .choose(MimeType.allOf())
        .countable(true)
        .maxSelectable(9)
        .addFilter(new GifSizeFilter(320, 320, 5 * Filter.K * Filter.K))
        .gridExpectedSize(getResources().getDimensionPixelSize(R.dimen.grid_expected_size))
        .restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
        .thumbnailScale(0.85f)
        .imageEngine(new GlideEngine())
        .forResult(REQUEST_CODE_CHOOSE);

大家有興趣可以去閱讀以下它的源碼险掀,另外這里面還應(yīng)用了其他模式沪袭,例如代理模式、模板方法等樟氢,這里會(huì)在后續(xù)的文章進(jìn)行介紹冈绊。

6. 總結(jié)

Abstract FactoryBuilder相似侠鳄,因?yàn)樗部梢詣?chuàng)建復(fù)雜對(duì)象。主要的區(qū)別就是Builder模式著重于一步步構(gòu)造一個(gè)復(fù)雜的對(duì)象死宣。而Abstract Factory著重于多個(gè)系列產(chǎn)品的對(duì)象的構(gòu)建伟恶。Builder在最后一步產(chǎn)品返回的時(shí)候,對(duì)于Abstract Factory來(lái)說毅该,產(chǎn)品是立即返回的博秫。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市眶掌,隨后出現(xiàn)的幾起案子挡育,更是在濱河造成了極大的恐慌,老刑警劉巖朴爬,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件即寒,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡召噩,警方通過查閱死者的電腦和手機(jī)母赵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蚣常,“玉大人市咽,你說我怎么就攤上這事〉治茫” “怎么了施绎?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)贞绳。 經(jīng)常有香客問我谷醉,道長(zhǎng),這世上最難降的妖魔是什么冈闭? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任俱尼,我火速辦了婚禮,結(jié)果婚禮上萎攒,老公的妹妹穿的比我還像新娘遇八。我一直安慰自己,他們只是感情好耍休,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布刃永。 她就那樣靜靜地躺著,像睡著了一般羊精。 火紅的嫁衣襯著肌膚如雪斯够。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音读规,去河邊找鬼抓督。 笑死,一個(gè)胖子當(dāng)著我的面吹牛束亏,可吹牛的內(nèi)容都是我干的铃在。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼枪汪,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼涌穆!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起雀久,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤宿稀,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后赖捌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體祝沸,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年越庇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了罩锐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡卤唉,死狀恐怖涩惑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情桑驱,我是刑警寧澤竭恬,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站熬的,受9級(jí)特大地震影響痊硕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜押框,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一岔绸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧橡伞,春花似錦盒揉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至道媚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背最域。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工谴分, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人镀脂。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓牺蹄,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親薄翅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子沙兰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容