静态工厂方法与传统构造方法
之前,我已經討論過一些關于Builder模式的信息 , Builder Pattern是一種有用的模式,用于實例化具有多個(可能是可選的)屬性的類,這些屬性可以使讀取,編寫和維護客戶端代碼更加容易,還有其他好處。 今天,我將繼續探索對象創建技術,但是這次是更一般的情況。
以下面的示例為例,除了說明我的觀點外,它絕不是有用的類。 顧名思義,我們有一個RandomIntGenerator類,它生成隨機的int數。 就像是:
我們的生成器采用最小值和最大值,然后生成這兩個值之間的隨機數。 注意,這兩個屬性都聲明為final,因此我們必須在它們的聲明或類構造函數中對其進行初始化。 讓我們來看一下構造函數:
public RandomIntGenerator(int min, int max) {this.min = min;this.max = max;}現在,我們還希望給客戶提供僅指定最小值的可能性,然后為該整數生成介于最小值和最大值之間的隨機值。 因此,我們添加了第二個構造函數:
public RandomIntGenerator(int min) {this.min = min;this.max = Integer.MAX_VALUE;}到目前為止一切順利,對嗎? 但是,就像我們提供一個僅指定最小值的構造函數一樣,我們只想為最大值做同樣的事情。 我們將只添加第三個構造函數,例如:
public RandomIntGenerator(int max) {this.min = Integer.MIN_VALUE;this.max = max;}如果嘗試這樣做,則會遇到以下編譯錯誤: 類型為RandomIntGenerator的重復方法RandomIntGenerator(int) 。 怎么了? 問題在于,根據定義,構造函數沒有名稱。 因此,一個類只能具有一個具有給定簽名的構造函數,而不能具有兩個具有相同簽名的方法(相同的返回類型,名稱和參數類型)。 這就是為什么當我們嘗試添加RandomIntGenerator(int max)構造函數時會出現該編譯錯誤的原因,因為我們已經有了RandomIntGenerator(int min)一個。
在這種情況下,我們可以做些什么嗎? 不是構造函數,但幸運的是,我們可以使用其他方法 : 靜態工廠方法 ,它們只是返回類實例的公共靜態方法。 您可能沒有意識到就使用了這種技術。 您曾經使用過Boolean.valueOf嗎? 看起來像:
public static Boolean valueOf(boolean b) {return (b ? TRUE : FALSE);}將靜態工廠應用于我們的RandomIntGenerator示例,我們可以獲得:
public class RandomIntGenerator {private final int min;private final int max;private RandomIntGenerator(int min, int max) {this.min = min;this.max = max;}public static RandomIntGenerator between(int max, int min) {return new RandomIntGenerator(min, max);}public static RandomIntGenerator biggerThan(int min) {return new RandomIntGenerator(min, Integer.MAX_VALUE);}public static RandomIntGenerator smallerThan(int max) {return new RandomIntGenerator(Integer.MIN_VALUE, max);}public int next() {...} }請注意,如何使構造函數私有化,以確保僅通過其公共靜態工廠方法實例化該類。 還要注意,當您的客戶端使用RandomIntGenerator.between(10,20)而不是new RandomIntGenerator(10,20)時,如何清楚地表達您的意圖。 值得一提的是,該技術與“ 四人幫”中的Factory方法設計模式不同。 任何類都可以提供靜態工廠方法來代替構造函數或在構造函數之外提供靜態方法。 那么,這種技術的優缺點是什么? 我們已經提到了靜態工廠方法的第一個優點:與構造函數不同,它們有名稱。 這有兩個直接的后果,
靜態工廠的另一個優點是,與構造函數不同,靜態工廠不需要在每次調用時都返回新對象。 當使用不可變的類為常用值提供常量對象并避免創建不必要的重復對象時,這非常有用。 我之前顯示的Boolean.valueOf代碼很好地說明了這一點。 請注意,此靜態方法返回TRUE或FALSE ,這兩個都是不可變的布爾對象。
靜態工廠方法的第三個優點是,它們可以返回其返回類型的任何子類型的對象。 這使您可以自由更改退貨類型而不會影響客戶。 此外,您可以隱藏實現類并擁有基于接口的API ,這通常是一個好主意。 但是我認為可以通過一個例子更好地看出這一點。
還記得本文開頭的RandomIntGenerator嗎? 讓我們稍微復雜一點。 想象一下,我們現在不僅要為整數提供隨機數生成器,還要為其他數據類型(如String,Double或Long)提供隨機數生成器。 它們都將具有next()方法,該方法返回特定類型的隨機對象,因此我們可以從如下接口開始:
public interface RandomGenerator<T> {T next(); }現在,我們對RandomIntGenerator第一個實現變為:
class RandomIntGenerator implements RandomGenerator<Integer> {private final int min;private final int max;RandomIntGenerator(int min, int max) {this.min = min;this.max = max;}public Integer next() {...} }我們還可以有一個String生成器:
class RandomStringGenerator implements RandomGenerator<String> {private final String prefix;RandomStringGenerator(String prefix) {this.prefix = prefix;}public String next() {...} } 請注意,如何將所有類聲明為包專用(默認范圍),以及它們的構造函數也是如此。 這意味著包之外的任何客戶端都無法創建這些生成器的實例。 那么我們該怎么辦? 提示:它以“靜態”開始,以“方法”結束。
考慮以下類別:
RandomGenerators只是一個RandomGenerators實用程序類,除了靜態工廠方法外別無其他。 與不同的生成器位于同一個包中,該類可以有效地訪問和實例化這些類。 但是有趣的部分到了。 請注意,這些方法僅返回RandomGenerator接口,而這正是客戶端真正需要的。 如果他們獲得了RandomGenerator<Integer>他們知道可以調用next()并獲得一個隨機整數。
想象一下,下個月我們將編寫一個超級高效的新整數生成器。 只要這個新類實現了RandomGenerator<Integer>我們就可以更改靜態工廠方法的返回類型,并且所有客戶端現在都在神奇地使用新實現,而他們甚至沒有注意到更改。
在JDK和第三方庫上,諸如RandomGenerators類的類都很常見。 您可以在Guava的 Collections (在java.util中), Lists , Sets或Maps中查看示例。 命名約定通常是相同的:如果您有一個名為Type的接口,則將您的靜態工廠方法放在一個名為Types不可實例化的類中。
靜態工廠的最后一個優點是,它們使實例化參數化的類的詳細程度降低了很多。 您是否曾經不得不編寫過這樣的代碼?
Map<String, List<String>> map = new HashMap<String, List<String>>();您在同一行代碼上重復相同的參數兩次。 如果可以從左側推斷出分配的右側,那會很好嗎? 好吧,有了靜態工廠就可以。 以下代碼摘自Guava的Maps類:
public static <K, V> HashMap<K, V> newHashMap() {return new HashMap<K, V>();}因此,現在我們的客戶代碼變為:
Map<String, List<String>> map = Maps.newHashMap();很好,不是嗎? 此功能稱為類型推斷 。 值得一提的是,Java 7通過使用菱形運算符引入了類型推斷。 因此,如果您使用的是Java 7,則可以將前面的示例編寫為:
Map<String, List<String>> map = new HashMap<>();靜態工廠的主要缺點是無法擴展沒有公共或受保護的構造函數的類。 但這在某些情況下實際上可能是一件好事,因為它鼓勵開發人員偏向于繼承而不是繼承 。
總而言之,靜態工廠方法提供了很多好處,但只有一個缺點,當您考慮它時,這實際上可能不是問題。 因此,抵制自動提供公共構造函數并評估靜態工廠是否更適合您的類的沖動。
參考: 開發時我們的JCG合作伙伴 Jose Luis的靜態工廠方法與傳統構造方法的比較 ,它應該是博客。
翻譯自: https://www.javacodegeeks.com/2013/01/static-factory-methods-vs-traditional-constructors.html
總結
以上是生活随笔為你收集整理的静态工厂方法与传统构造方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 魅族 20 独白机型新增 12GB+25
- 下一篇: 曝小米13T Pro将于9月16日全球发