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