詳解 - Builder模式

Burjal本尊發表於2017-12-21

Android設計模式”這個系列主要是對Android專案中的設計模式進行分析總結,學習自《Android 原始碼設計模式解析與實戰》,錯誤之處煩請指正~


Android設計模式系列文章:

1、詳解 - 單例模式 2、詳解 - Builder模式


一、 概述

1.1 定義

將一個複雜物件的構建與表示分離開來,使得同樣的構建過程可以建立不同的表示。

1.2 使用場景

  • 相同的方法,不同的執行順序,產生不同的結果

  • 多中屬性都可以裝配到一個物件中,但是產生的執行結果不同

  • 複雜的產品類,或者產品類結果會隨呼叫順序發生改變

  • 初始化一個物件特別複雜,如引數特別多,且很多引數都具有預設值時

1.3 分析

Builder模式將部件和組裝過程分離,使得構建過程和部件都可以自由擴充套件,從而降低兩者耦合度。

優點:

  • 良好的封裝性,使用Builder模式可以使客戶端不必知道產品內部的組成細節
  • Builder獨立,易於擴充套件

缺點:

  • 會產生冗餘的Builder物件以及組裝物件,消耗記憶體

二、 實現

2.1 示例

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

EventBus 框架中的 EventBusBuilder 就採用 Builder 模式實現,我們來分析Builder模式的實現,EventBus 3.0 原始碼解析見 EventBus3.原始碼解析

EventBusBuilderEventBus 框架中的個性化配置類,從類名就可以看出這是一個 Builder 模式,通過Builder 物件來組裝個性化設定 EventBus 的各項引數配置,包括 是否通過Log輸出異常資訊logSubscriberExceptions 等。下面看看 EventBusBuilder 的相關原始碼。

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

    boolean logSubscriberExceptions = true;//是否通過Log輸出異常資訊
    boolean logNoSubscriberMessages = true;//是否通過Log輸出傳送事件無訂閱者資訊
    boolean sendSubscriberExceptionEvent = true;//是否將內部異常資訊通過SubscriberExceptionEvent傳送出去
    boolean sendNoSubscriberEvent = true;//是否將無訂閱者的時間通過NoSubscriberEvent傳送出去
    boolean throwSubscriberException;//是否將內部異常資訊通過EventBusException丟擲
    boolean eventInheritance = true;//傳送事件是否支援呼叫所有父類及實現的介面
    boolean ignoreGeneratedIndex;//是否忽略生成被觀察者訂閱的方法(通過反射)
    boolean strictMethodVerification;//是否開啟嚴格的方法驗證,(public,只有一個引數,不為static及abstract),非法則均丟擲異常
    ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;//傳送事件的執行緒池
    List<Class<?>> skipMethodVerificationForClasses;//對類忽略方法校驗,目前未實現
    List<SubscriberInfoIndex> subscriberInfoIndexes;//通過annotation preprocessor生成的訂閱者方法list

    EventBusBuilder() {
    }

    /**
     * 設定 logSubscriberExceptions,預設為true
     * @param logSubscriberExceptions
     * @return
     */
    public EventBusBuilder logSubscriberExceptions(boolean logSubscriberExceptions) {
        this.logSubscriberExceptions = logSubscriberExceptions;
        return this;
    }

    /**
     * 設定 logNoSubscriberMessages,預設為 true
     * @param logNoSubscriberMessages
     * @return
     */
    public EventBusBuilder logNoSubscriberMessages(boolean logNoSubscriberMessages) {
        this.logNoSubscriberMessages = logNoSubscriberMessages;
        return this;
    }

    /**
     * 設定 sendSubscriberExceptionEvent,預設為 true
     * @param sendSubscriberExceptionEvent
     * @return
     */
    public EventBusBuilder sendSubscriberExceptionEvent(boolean sendSubscriberExceptionEvent) {
        this.sendSubscriberExceptionEvent = sendSubscriberExceptionEvent;
        return this;
    }

    /**
     * 設定 sendNoSubscriberEvent,預設為 true
     * @param sendNoSubscriberEvent
     * @return
     */
    public EventBusBuilder sendNoSubscriberEvent(boolean sendNoSubscriberEvent) {
        this.sendNoSubscriberEvent = sendNoSubscriberEvent;
        return this;
    }

    /**
     * 設定 throwSubscriberException,預設為 false
     * @param throwSubscriberException
     * @return
     */
    public EventBusBuilder throwSubscriberException(boolean throwSubscriberException) {
        this.throwSubscriberException = throwSubscriberException;
        return this;
    }

    /**
     * 設定 eventInheritance,預設為 true
     * @param eventInheritance
     * @return
     */
    public EventBusBuilder eventInheritance(boolean eventInheritance) {
        this.eventInheritance = eventInheritance;
        return this;
    }


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

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

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

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

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

    /**
     * 實現修改 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 方式實現 EventBus 初始化
     * @return
     */
    public EventBus build() {
        return new EventBus(this);
    }

}
複製程式碼

上述程式碼中,EventBusBuilder 類可以設定 EventBus 中的 * logSubscriberExceptions、logNoSubscriberMessages、sendSubscriberExceptionEvent* 等引數,這些引數統一儲存在 EventBusBuilder 中。在呼叫 EventBusBuilder 類的 build() 函式時會建立 EventBus,並且將各項配置用於到 EventBus 中去。

EventBusBuilder 採用 Builder 模式主要是初始化 EventBus 配置項引數複雜,並且很多引數具有預設值,在使用時可能只需要對部分引數進行修改,故採用 Builder 模式方便修改初始化。

2.2 小結

通過 2.1節 可以看出 Builder 模式使用非常方便,並且對於多引數屬性初始化來說,極大的簡化了工作。

在專案中合理的加入 Builder 模式吧~

三、小結

Builder 模式在 Android 開發中較為常用,通常作為配置類的構造器將配置的構建和表示分離開來,同時也實現了將配置類從目標類中抽離出來,避免了過多的 setter 方法。

Builder 模式比較常見的實現方式是通過呼叫鏈實現,這樣使得程式碼簡單易懂。


本文對 Builder模式 的分析到此就結束了,部分內容學習自 《Android原始碼設計模式 解析與實戰》

附:

EventBus3(3.0.0)原始碼解析

相關文章