創(chuàng)建者模式的特點及使用場景
《Effective Java》—— 創(chuàng)建與銷毀對象 一章中有寫道:當(dāng)一個類中有大量的構(gòu)造參數(shù)時,靜態(tài)方法和構(gòu)造器已經(jīng)不能滿足對象的實例化嚎研,那么我們將考慮構(gòu)建器蝌蹂。
構(gòu)建器模式:
- 1噩斟、重疊構(gòu)造器模式
- 2、javaBeans模式(自己常用的一種)
- 3叉信、builder模式
說明:
- 重疊構(gòu)造器模式:這種模式下亩冬,提供第一個只有必要參數(shù)的構(gòu)造器艘希,第二個構(gòu)造器有一個可選參數(shù)硼身,第三個有兩個可選參數(shù),以此類推覆享,最后一個構(gòu)造器包含所有可選參數(shù)佳遂。
- javaBeans模式:調(diào)用在各分無參構(gòu)造器創(chuàng)建對象,然后調(diào)用setter方法來設(shè)置每個必要的參數(shù)撒顿,以及每個相關(guān)的可選參數(shù)丑罪。
- builder模式:builder像個構(gòu)造器一樣,可以對其參數(shù)強加約束條件。build方法可以檢驗這些約束條件吩屹。將參數(shù)從builder拷貝到對象中之后跪另,并在對象域而不是builder域中對它們進(jìn)行檢驗,這一點很重要煤搜。如果違反了人格約束條件免绿,build方法就應(yīng)該拋出IllegalStateException。異常的詳細(xì)信息應(yīng)該顯示出違反哪個約束條件擦盾。
從上不難看出:
- 重疊構(gòu)造器模式在參數(shù)很多的情況下嘲驾,客戶端代碼會很難寫,并且難以閱讀迹卢。
- javaBeans模式因為構(gòu)造過程分到了幾個調(diào)用中辽故,在構(gòu)造過程中javaBean可能處于不一致的狀態(tài),類無法僅僅通過校驗構(gòu)造參數(shù)的* 有效性來保證一致性腐碱。這樣程序員需要付出額外的努力來確保它的線程安全
- builder模式技能保證像重疊構(gòu)造器模式那樣的安全性誊垢,也能保證像javaBeans模式那么好的可讀性。
builder模式十分靈活喻杈,可以利用單個builder構(gòu)建多個對象彤枢。builder的參數(shù)可以在創(chuàng)建對象期間進(jìn)行調(diào)整,也可以隨著不同的對象而改變筒饰。
代碼示例
class DefaultHttpClientFactory {
private static PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
private static RequestConfig defaultRequestConfig = RequestConfig.custom().build();
private static int mgrMaxTotal = DEFAULT_MAX_TOTAL; //全局最大連接數(shù)
private static int mgrDefaultMaxPerRoute = DEFAULT_MAX_PER_ROUTE; //每個主機最大連接數(shù)
private static int connReqTimeout = DEFAULT_CONN_REQ_TIMEOUT; //從連接池獲取連接超時時間
private static int connTimout = DEFAULT_CONN_TIMEOUT; //發(fā)起連接超時時間
private static int connSocketTimeout = DEFAULT_CONN_SOCKET_TIMEOUT; //連接套接字等待時間
public static class Builder {
private int mgrMaxTotal = DEFAULT_MAX_TOTAL; //全局最大連接數(shù)
private int mgrDefaultMaxPerRoute = DEFAULT_MAX_PER_ROUTE; //每個主機最大連接數(shù)
private int connReqTimeout = DEFAULT_CONN_REQ_TIMEOUT; //從連接池獲取連接超時時間
private int connTimout = DEFAULT_CONN_TIMEOUT; //發(fā)起連接超時時間
private int connSocketTimeout = DEFAULT_CONN_SOCKET_TIMEOUT; //連接套接字等待時間
Builder() {
}
public Builder maxTotal(int maxTotal) {
this.mgrMaxTotal = maxTotal;
return this;
}
public Builder maxPerRoute(int maxPerRoute) {
this.mgrDefaultMaxPerRoute = maxPerRoute;
return this;
}
public Builder connReqTimeout(int connReqTimeout) {
this.connReqTimeout = connReqTimeout;
return this;
}
public Builder connTimout(int connTimout) {
this.connTimout = connTimout;
return this;
}
public Builder connSocketTimeout(int connSocketTimeout) {
this.connSocketTimeout = connSocketTimeout;
return this;
}
public DefaultHttpClientFactory build() {
return new DefaultHttpClientFactory(this);
}
}
private DefaultHttpClientFactory(Builder builder) {
mgrMaxTotal = builder.mgrMaxTotal;
mgrDefaultMaxPerRoute = builder.mgrDefaultMaxPerRoute;
connReqTimeout = builder.connReqTimeout;
connTimout = builder.connTimout;
connSocketTimeout = builder.connSocketTimeout;
}
public static DefaultHttpClientFactory.Builder custom() {
return new DefaultHttpClientFactory.Builder();
}
public CloseableHttpClient getClient() {
cm.setMaxTotal(mgrMaxTotal); // 設(shè)置最大連接數(shù)
cm.setDefaultMaxPerRoute(mgrDefaultMaxPerRoute); // 設(shè)置每個路由最大連接數(shù)缴啡,每個獨立的host為1個路由
RequestConfig requestConfig = RequestConfig.copy(defaultRequestConfig)
.setConnectionRequestTimeout(connReqTimeout)//從連接池獲取連接超時時間
.setConnectTimeout(connTimout)//發(fā)起連接超時時間
.setSocketTimeout(connSocketTimeout)//連接套接字等待時間
.setRedirectsEnabled(false)
.build();
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
httpClientBuilder.setConnectionManager(cm);
httpClientBuilder.setDefaultRequestConfig(requestConfig);
httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(0, false)); // 去掉默認(rèn)的3次重試
CloseableHttpClient httpClient = httpClientBuilder.build();
return httpClient;
}
}
歡迎關(guān)注 高廣超的簡書博客 與 收藏文章 !
個人介紹:
** 高廣超** :多年一線互聯(lián)網(wǎng)研發(fā)與架構(gòu)設(shè)計經(jīng)驗瓷们,擅長設(shè)計與落地高可用业栅、高性能互聯(lián)網(wǎng)架構(gòu)。目前就職于美團(tuán)網(wǎng)谬晕,負(fù)責(zé)核心業(yè)務(wù)研發(fā)工作碘裕。
本文首發(fā)在 高廣超的簡書博客 轉(zhuǎn)載請注明!