ej3-1優先使用靜態工廠方法而非構造函數來建立對象

背景

很早以前就已經本身翻譯了,先簡單的貼出來,並作一下回顧。

條款1 優先使用靜態工廠方法而非構造函數來建立對象

容許客戶端建立一個實例的傳統方法是:提供一個公共構造函數;有另一個必須成爲每一個程序員的編程技巧:優先使用類提供的只簡單返回實例的公共靜態工廠方法來建立對象。這有一個簡單的Boolean類的例子:這個方法轉換一個原生的boolean類型的值爲一個Boolean的實例。
public static Boolean valueOf(boolean b){
        return b?Boolean.TRUE:Boolean.FALSE;
  }
注意這一點:類的靜態工廠方法不一樣於設計模式的工廠設計模式。本條規約跟設計模式沒有關聯。
一個類能夠經過靜態工廠方法也可使用公共構造函數提供給本身的客戶端調用來建立實例,使用靜態工廠方法而不是公共構造函數有優勢也有缺點。

優勢1:它有名字,可讀性更好;java

構造函數的參數跟本身無關,沒有描述返回對象;而良好命名的靜態工廠方法客戶端代碼可讀性更好,因此更容易使用;
//使用構造方法,返回一個BigInteger隨機素數;
BigInteger(int , int , Random)
//更好的表達方式  
public static BigInteger probablePrime();
一個類構造函數的簽名格式是惟一的,程序員圍繞這個限制提供了兩個構造函數,他們區分的標準是不同參數的類型組成的參數列表,這真的是一個糟糕的設計,使用這種API的人歷來就沒辦法記住哪一個構造函數對應哪一個功能,而且容易誤用致使調用錯誤;使用這些構造函數的人只能閱讀代碼,類文檔無法區分。

由於靜態工廠方法有名字,因此不存在區分的限制,在一個類有多個簽名的構造函數的場景中,應該使用靜態工廠方法替代構造函數,而且當心選擇名字來區別;程序員

優勢2:不須要每次被調用的時候都建立一個新的對象;編程

這容許構造完畢的不可變類使用提早構建或者緩存的實例,避免建立沒必要要的重複的對象(分配重複的實例); Boolean.valueOf(boolean) 方法展現了這個技巧,它歷來不建立對象,這個技巧相似於享元模式;若是建立代價昂貴的對象被頻繁獲取,它能夠顯著的提升性能;這個能力可讓類在任什麼時候刻嚴格控制實例,這樣的類叫作實例可控類,有幾個理由應該編寫實例可控類:
  1. 實例可控使類須要保證它是單例的實例數量可控;
  2. 須要保證沒有兩個相同的實例存在;若是a.equls(b) ; 有且只有a == b. 這是基本的享元模式。枚舉類型提供了這個保證;

優勢3:能夠返回子類型,面向抽象編程或者說是接口編程,更靈活;設計模式

一個靈活的應用API能夠返回非公開的對象,隱藏實現類從而造成契約API,這個技巧使得它能夠成爲基於接口的框架,接口提供天然的返回類型,(在java8以前,接口沒有靜態的方法,按照慣例,接口Type靜態工廠方法被放到了一個不可實例化的指南類Types中;)

舉個例子:java的Collections接口框架有45個種不一樣的應用實現,提供不可修改集合,同步集合等,幾乎全部的這些實現經過一個不可實例化的類Collections的靜態工廠方法來對外暴露;全部的返回對象都是非公開的的(即實際返回的是接口實現類或者返回類的子類)。這個集合框架的API比定義45個分開獨立的公共類規模要小不少(它減小了集合類的數量負擔,也減小了程序員必須掌握使用的API的類數量),程序員知道返回的對象精確的指出了它的接口,因此沒有必要去閱讀更多的實現類的文檔。更進一步,使用這樣一個靜態工廠方法的客戶端只須要參照接口而不用考慮實現類去使用,這是一個最佳實踐。緩存

在java8中,接口已經能夠添加靜態方法了,因此接口能夠提供一個不可實例的有常規名字的指南類;接口的不少的公共靜態成員放應該替代成接口自己。然而,仍然有必要把這樣一個靜態工廠方法實現代碼放到分開的private 包下的類中;這是由於java8要求接口的靜態成員必須是public,java9容許私有的靜態方法,可是靜態成員和靜態內部類任然須要是public的;框架

原創不易,轉載請註明出處,歡迎溝通交流。
相關文章
相關標籤/搜索