遇到構造器有多個參數時要考慮用建造者模式
靜態工廠方法和構造器都有一個侷限性:
當構造的對象有大量的可選參數時,你可能需要定義很多個靜態工廠方法或者構造器。
用setter方法替代多參數構造器的幾個缺點
書中提到多參數的構造器的一個替代方法,就是用JavaBean模式:使用無參構造器創建對象,然後調用setter方法設置每個必要參數以及一些可選參數。
1. 構造的過程中,對象可能處於不一致的狀態
2. 因爲有setter方法,所以阻止了這個對象成爲不可變(unmodifiable)對象
爲了避免以上的這些問題,就需要我們把構造對象的過程抽離出來,這也是建造者模式(Builder Pattern)的設計初衷。
對於建造者模式,JDK中的例子都不是很典型,所以我就舉OkHttp中的一兩個例子。
事實上,涉及到Http協議的庫都大量的使用到建造者模式,因爲Http中的可配置的參數實在太多了。
從創建OkHttpClient對象開始:
OkHttpClient httpClient = new OkHttpClient.Builder()
.cache(cache) // 緩存響應數據
.connectionPool(connectionPool) // 連接池
.cookieJar(cookieJar) // Cookie存儲策略
.addInterceptor(interceptor) // 攔截器
... // 其他可選的配置項
.build(); // 最後創建OkHttpClient對象
創建OkHttpClient時,可以指定很多可選配置,上面只是舉了幾個最常用的配置選項,其他你沒有進行配置的選項都會使用默認的配置。創建OkHttpClient對象後你就不能再修改這個OkHttpClient對象的屬性了:OkHttpClient中不提供這些屬性的setter方法;對於一些集合屬性(比如攔截器),它都是用Collections.unmodifiableXxx進行了包裝,防止調用者進行修改。
創建請求也是一個典型的構建者模式:
Request request = new Request.Builder()
.get()
.url("https://www.baidu.com")
.addHeader("Accept-Language", "zh-CN")
.addHeader("User-Agent", "Chrome/63.0.3239.84")
.build();
這裏設置請求頭,可以設置若干個,很明顯比用構造器靈活的多。