詳解 - Builder模式

Android設(shè)計模式”這個系列主要是對Android項目中的設(shè)計模式進行分析總結(jié),學(xué)習(xí)自《Android 源碼設(shè)計模式解析與實戰(zhàn)》,錯誤之處煩請指正~


Android設(shè)計模式系列文章:

1描函、詳解 - 單例模式
2狐粱、詳解 - Builder模式


一、 概述

1.1 定義

將一個復(fù)雜對象的構(gòu)建與表示分離開來互墓,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示蒋搜。

1.2 使用場景

  • 相同的方法,不同的執(zhí)行順序豆挽,產(chǎn)生不同的結(jié)果

  • 多中屬性都可以裝配到一個對象中帮哈,但是產(chǎn)生的運行結(jié)果不同

  • 復(fù)雜的產(chǎn)品類,或者產(chǎn)品類結(jié)果會隨調(diào)用順序發(fā)生改變

  • 初始化一個對象特別復(fù)雜,如參數(shù)特別多泳炉,且很多參數(shù)都具有默認值時

1.3 分析

Builder模式將部件和組裝過程分離嚎杨,使得構(gòu)建過程和部件都可以自由擴展,從而降低兩者耦合度刨肃。

優(yōu)點:

  • 良好的封裝性自脯,使用Builder模式可以使客戶端不必知道產(chǎn)品內(nèi)部的組成細節(jié)
  • Builder獨立,易于擴展

缺點:

  • 會產(chǎn)生冗余的Builder對象以及組裝對象膏潮,消耗內(nèi)存

二焕参、 實現(xiàn)

2.1 示例

Builder模式非常易于上手,我們通過分析一個簡單的demo來感受Builder模式的魅力叠纷。

EventBus 框架中的 EventBusBuilder 就采用 Builder 模式實現(xiàn),我們來分析Builder模式的實現(xiàn)崇众,EventBus 3.0 源碼解析見 EventBus3.源碼解析航厚。

EventBusBuilderEventBus 框架中的個性化配置類,從類名就可以看出這是一個 Builder 模式眯漩,通過Builder 對象來組裝個性化設(shè)置 EventBus 的各項參數(shù)配置麻顶,包括 是否通過Log輸出異常信息logSubscriberExceptions 等。下面看看 EventBusBuilder 的相關(guān)源碼辅肾。

public class EventBusBuilder {
    private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();

    boolean logSubscriberExceptions = true;//是否通過Log輸出異常信息
    boolean logNoSubscriberMessages = true;//是否通過Log輸出發(fā)送事件無訂閱者信息
    boolean sendSubscriberExceptionEvent = true;//是否將內(nèi)部異常信息通過SubscriberExceptionEvent發(fā)送出去
    boolean sendNoSubscriberEvent = true;//是否將無訂閱者的時間通過NoSubscriberEvent發(fā)送出去
    boolean throwSubscriberException;//是否將內(nèi)部異常信息通過EventBusException拋出
    boolean eventInheritance = true;//發(fā)送事件是否支持調(diào)用所有父類及實現(xiàn)的接口
    boolean ignoreGeneratedIndex;//是否忽略生成被觀察者訂閱的方法(通過反射)
    boolean strictMethodVerification;//是否開啟嚴格的方法驗證,(public,只有一個參數(shù),不為static及abstract),非法則均拋出異常
    ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;//發(fā)送事件的線程池
    List<Class<?>> skipMethodVerificationForClasses;//對類忽略方法校驗矫钓,目前未實現(xiàn)
    List<SubscriberInfoIndex> subscriberInfoIndexes;//通過annotation preprocessor生成的訂閱者方法list

    EventBusBuilder() {
    }

    /**
     * 設(shè)置 logSubscriberExceptions,默認為true
     * @param logSubscriberExceptions
     * @return
     */
    public EventBusBuilder logSubscriberExceptions(boolean logSubscriberExceptions) {
        this.logSubscriberExceptions = logSubscriberExceptions;
        return this;
    }

    /**
     * 設(shè)置 logNoSubscriberMessages,默認為 true
     * @param logNoSubscriberMessages
     * @return
     */
    public EventBusBuilder logNoSubscriberMessages(boolean logNoSubscriberMessages) {
        this.logNoSubscriberMessages = logNoSubscriberMessages;
        return this;
    }

    /**
     * 設(shè)置 sendSubscriberExceptionEvent,默認為 true
     * @param sendSubscriberExceptionEvent
     * @return
     */
    public EventBusBuilder sendSubscriberExceptionEvent(boolean sendSubscriberExceptionEvent) {
        this.sendSubscriberExceptionEvent = sendSubscriberExceptionEvent;
        return this;
    }

    /**
     * 設(shè)置 sendNoSubscriberEvent,默認為 true
     * @param sendNoSubscriberEvent
     * @return
     */
    public EventBusBuilder sendNoSubscriberEvent(boolean sendNoSubscriberEvent) {
        this.sendNoSubscriberEvent = sendNoSubscriberEvent;
        return this;
    }

    /**
     * 設(shè)置 throwSubscriberException,默認為 false
     * @param throwSubscriberException
     * @return
     */
    public EventBusBuilder throwSubscriberException(boolean throwSubscriberException) {
        this.throwSubscriberException = throwSubscriberException;
        return this;
    }

    /**
     * 設(shè)置 eventInheritance,默認為 true
     * @param eventInheritance
     * @return
     */
    public EventBusBuilder eventInheritance(boolean eventInheritance) {
        this.eventInheritance = eventInheritance;
        return this;
    }


    /**
     * 設(shè)置 executorService
     * @param executorService
     * @return
     */
    public EventBusBuilder executorService(ExecutorService executorService) {
        this.executorService = executorService;
        return this;
    }

    /**
     * 設(shè)置 skipMethodVerificationForClasses
     * @param clazz
     * @return
     */
    public EventBusBuilder skipMethodVerificationFor(Class<?> clazz) {
        if (skipMethodVerificationForClasses == null) {
            skipMethodVerificationForClasses = new ArrayList<>();
        }
        skipMethodVerificationForClasses.add(clazz);
        return this;
    }

    /**
     * 設(shè)置 ignoreGeneratedIndex
     * @param ignoreGeneratedIndex
     * @return
     */
    public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) {
        this.ignoreGeneratedIndex = ignoreGeneratedIndex;
        return this;
    }

    /**
     * 設(shè)置 strictMethodVerification
     * @param strictMethodVerification
     * @return
     */
    public EventBusBuilder strictMethodVerification(boolean strictMethodVerification) {
        this.strictMethodVerification = strictMethodVerification;
        return this;
    }

    /**
     * 設(shè)置 subscriberInfoIndexes
     * @param index
     * @return
     */
    public EventBusBuilder addIndex(SubscriberInfoIndex index) {
        if(subscriberInfoIndexes == null) {
            subscriberInfoIndexes = new ArrayList<>();
        }
        subscriberInfoIndexes.add(index);
        return this;
    }

    /**
     * 實現(xiàn)修改 EventBus 默認 EventBusBuilder(EventBus.defaultInstance)
     * @return
     */
    public EventBus installDefaultEventBus() {
        synchronized (EventBus.class) {
            if (EventBus.defaultInstance != null) {
                throw new EventBusException("Default instance already exists." +
                        " It may be only set once before it's used the first time to ensure consistent behavior.");
            }
            EventBus.defaultInstance = build();
            return EventBus.defaultInstance;
        }
    }

    /**
     * 通過 build 方式實現(xiàn) EventBus 初始化
     * @return
     */
    public EventBus build() {
        return new EventBus(this);
    }

}

上述代碼中盈电,EventBusBuilder 類可以設(shè)置 EventBus 中的 * logSubscriberExceptions匆帚、logNoSubscriberMessages旁钧、sendSubscriberExceptionEvent* 等參數(shù),這些參數(shù)統(tǒng)一存儲在 EventBusBuilder 中歪今。在調(diào)用 EventBusBuilder 類的 build() 函數(shù)時會創(chuàng)建 EventBus,并且將各項配置用于到 EventBus 中去嫉晶。

EventBusBuilder 采用 Builder 模式主要是初始化 EventBus 配置項參數(shù)復(fù)雜田篇,并且很多參數(shù)具有默認值,在使用時可能只需要對部分參數(shù)進行修改泊柬,故采用 Builder 模式方便修改初始化。

2.2 小結(jié)

通過 2.1節(jié) 可以看出 Builder 模式使用非常方便状答,并且對于多參數(shù)屬性初始化來說刀崖,極大的簡化了工作。

在項目中合理的加入 Builder 模式吧~

三译断、小結(jié)

Builder 模式在 Android 開發(fā)中較為常用或悲,通常作為配置類的構(gòu)造器將配置的構(gòu)建和表示分離開來,同時也實現(xiàn)了將配置類從目標類中抽離出來巡语,避免了過多的 setter 方法。

Builder 模式比較常見的實現(xiàn)方式是通過調(diào)用鏈實現(xiàn)荤堪,這樣使得代碼簡單易懂。


本文對 Builder模式 的分析到此就結(jié)束了澄阳,部分內(nèi)容學(xué)習(xí)自 《Android源碼設(shè)計模式 解析與實戰(zhàn)》

附:

EventBus3(3.0.0)源碼解析

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末低剔,一起剝皮案震驚了整個濱河市肮塞,隨后出現(xiàn)的幾起案子枕赵,更是在濱河造成了極大的恐慌,老刑警劉巖拷窜,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件装黑,死亡現(xiàn)場離奇詭異副瀑,居然都是意外死亡恋谭,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門狈孔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來均抽,“玉大人其掂,你說我怎么就攤上這事】畎荆” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵惋鹅,是天一觀的道長殉簸。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么宁昭? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮盲链,結(jié)果婚禮上迟杂,老公的妹妹穿的比我還像新娘本慕。我一直安慰自己,他們只是感情好监氢,可當我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布藤违。 她就那樣靜靜地躺著,像睡著了一般议街。 火紅的嫁衣襯著肌膚如雪璧榄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天涂身,我揣著相機與錄音搓蚪,去河邊找鬼。 笑死妒潭,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的杜耙。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼记靡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了空凸?” 一聲冷哼從身側(cè)響起寸痢,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎道逗,沒想到半個月后献烦,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡吏夯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年即横,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跺嗽。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡页藻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惕橙,到底是詐尸還是另有隱情,我是刑警寧澤肚逸,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布彬坏,位于F島的核電站,受9級特大地震影響务冕,放射性物質(zhì)發(fā)生泄漏幻赚。R本人自食惡果不足惜禀忆,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一箩退、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧戴涝,春花似錦、人聲如沸奸鸯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蘑拯。三九已至兜粘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間剃法,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工贷洲, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留晋柱,地道東北人。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓钦椭,卻偏偏與公主長得像碑诉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子德挣,可洞房花燭夜當晚...
    茶點故事閱讀 43,452評論 2 348

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,735評論 25 707
  • 本文首發(fā)于個人博客:Lam's Blog - 談?wù)?3種設(shè)計模式在Android源碼及項目中的應(yīng)用格嗅,文章由Mark...
    格子林ll閱讀 4,632評論 1 105
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)建芙,斷路器,智...
    卡卡羅2017閱讀 134,628評論 18 139
  • 人生就只如初見禁荸。 ___________________________________嚴薇 遇見之前阀湿,懵懵懂懂的...
    羅嫚閱讀 426評論 2 10
  • 這里是安寧世界陷嘴。 歡迎來聊天映砖。 做了很多年數(shù)據(jù)信息的工作灾挨,謀算人心和金錢,卻對文字總是念念不忘劳澄。 今天在雍和宮拍下...
    V_A閱讀 140評論 0 0