Builder模式
使用Google calendar v3 API的時候,大量發現Builder使用。比如Credential類,查了查Builder模式的講解,始終感覺代碼的實現和標準定義不太相同。最后發現這種實現方式是《Effective java 2nd》中的一種實現(Item 2: Consider a builder when faced with many constructor parameters)。靜態工廠和構造器都有一個通病:對于存在大量可選構造參數的對象,擴展性不好。經典的解決方案是提供多個構造函數,第一個構造函數只有必須的參數,第二個構造函數除了必須參數還有一個可選參數,第三個除了必須參數還有兩個可選參數。。。這樣下去知道最后一個可選參數出現(telescoping constructor)。這種方案的問題是,當構建對象的時候很容易把其中兩個參數的位置放反。。。。(難發現的bug)。
另一種解決方案是JavaBean 模式,先調用無參構造函數再調用各個set方法來組裝對象。這種方案的問題是不能強制一致性。如果沒有set某些必須的參數的話,對象可能處于不一致(
同時Builder類設置為static也是對Item 22:Favor static member classes over nonstatic的實踐
inconsistent)的狀態(難發現的bug)。另外一個缺點是JavaBean模式不能讓類immutable,需要程序員額外工作保證線程安全。
第三種方式就是Builder設計模式。這種方式混合了telescoping constructor模式的安全性和JavaBean模式的可讀性。客戶端調用有所有必填參數的構造器(或靜態工廠),得到一個builder對象。然后調用builder對象的方法去set各個選填參數。最后調用無參的build方法產生一個immutable的對象實例。immutable對象有非常多優點而且可能很有用。builder的set方法都是返回builder本身,所以調用也是可以chained。如: GoogleCredential credentialNew = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY).setClientSecrets(clientSecrets)
.addRefreshListener(new CredentialStoreRefreshListener(userID, new DBCredentialStore())).build()
.setAccessToken(accessToken).setRefreshToken(refreshToken)
客戶端代碼很好寫,更重要的是易讀。Builder模式模擬了在Ada和Python語言里的命名可選參數(named optional parameters)。.setJsonFactory(JSON_FACTORY).setClientSecrets(clientSecrets)
.addRefreshListener(new CredentialStoreRefreshListener(userID, new DBCredentialStore())).build()
.setAccessToken(accessToken).setRefreshToken(refreshToken)
同時Builder類設置為static也是對Item 22:Favor static member classes over nonstatic的實踐
posted on 2012-05-30 17:44 yuxh 閱讀(398) 評論(0) 編輯 收藏 所屬分類: 設計模式 、work