日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

构造函数还是静态工厂方法?

發布時間:2023/12/3 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 构造函数还是静态工厂方法? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

我相信Joshua Bloch在他的非常好的書“ Effective Java”中首先說了它:與構造函數相比,靜態工廠方法是實例化對象的首選方法。 我不同意。 不僅因為我相信靜態方法是純粹的邪惡,而且主要是因為在這種特殊情況下,它們偽裝成好的方法,使我們認為我們必須愛上它們。

摘錄(2009),作者:麥克·賈奇(Mike Judge)

讓我們從面向對象的角度分析推理并查看其原因。

這是一個具有一個主要構造函數和兩個次要構造函數的類:

class Color {private final int hex;Color(String rgb) {this(Integer.parseInt(rgb, 16));}Color(int red, int green, int blue) {this(red << 16 + green << 8 + blue);}Color(int h) {this.hex = h;} }

這是帶有三個靜態工廠方法的類似類:

class Color {private final int hex;static Color makeFromRGB(String rgb) {return new Color(Integer.parseInt(rgb, 16));}static Color makeFromPalette(int red, int green, int blue) {return new Color(red << 16 + green << 8 + blue);}static Color makeFromHex(int h) {return new Color(h);}private Color(int h) {return new Color(h);} }

你更喜歡哪一個?

據約書亞布洛赫,但使用靜態工廠方法而不是構造函數(一共設置了四個,但第四個是不是適用于Java的三個基本優勢了 ):

  • 他們有名字。
  • 他們可以緩存。
  • 它們可以是子類型。

我認為,如果設計錯誤,那么這三者都是完全合理的。 它們是解決方法的好借口。 讓我們一一介紹。

他們有名字

這是使用構造函數制作紅色番茄顏色對象的方法:

Color tomato = new Color(255, 99, 71);

這是使用靜態工廠方法執行的操作:

Color tomato = Color.makeFromPalette(255, 99, 71);

看起來makeFromPalette()在語義上比new Color()更豐富,對嗎? 嗯,是。 如果我們將它們傳遞給構造函數,誰知道這三個數字意味著什么。 但是“調色板”一詞可以幫助我們立即解決所有問題。

真正。

但是,正確的解決方案是使用多態和封裝,以將問題分解為幾個語義豐富的類:

interface Color { } class HexColor implements Color {private final int hex;HexColor(int h) {this.hex = h;} } class RGBColor implements Color {private final Color origin;RGBColor(int red, int green, int blue) {this.origin = new HexColor(red << 16 + green << 8 + blue);} }

現在,我們使用正確的類的正確的構造函數:

Color tomato = new RGBColor(255, 99, 71);

看,約書亞?

他們可以緩存

假設我在應用程序中的多個位置需要一個紅色的番茄色:

Color tomato = new Color(255, 99, 71); // ... sometime later Color red = new Color(255, 99, 71);

將創建兩個對象,這顯然是低效的,因為它們是相同的。 最好將第一個實例保留在內存中的某個位置,并在第二個調用到達時將其返回。 靜態工廠方法可以解決這個問題:

Color tomato = Color.makeFromPalette(255, 99, 71); // ... sometime later Color red = Color.makeFromPalette(255, 99, 71);

然后,在Color內的某個地方,我們保留了一個私有靜態Map ,其中已實例化了所有對象:

class Color {private static final Map<Integer, Color> CACHE =new HashMap<>();private final int hex;static Color makeFromPalette(int red, int green, int blue) {final int hex = red << 16 + green << 8 + blue;return Color.CACHE.computeIfAbsent(hex, h -> new Color(h));}private Color(int h) {return new Color(h);} }

這是非常有效的性能。 對于像我們的Color這樣的小對象,問題可能并不那么明顯,但是當對象較大時,其實例化和垃圾回收可能會浪費大量時間。

真正。

但是,有一種面向對象的方法可以解決此問題。 我們只是介紹了一個新類Palette ,它變成了一個顏色存儲區:

class Palette {private final Map<Integer, Color> colors =new HashMap<>();Color take(int red, int green, int blue) {final int hex = red << 16 + green << 8 + blue;return this.computerIfAbsent(hex, h -> new Color(h));} }

現在,我們一次創建一個Palette實例,并要求它在每次需要時向我們返回一種顏色:

Color tomato = palette.take(255, 99, 71); // Later we will get the same instance: Color red = palette.take(255, 99, 71);

見,約書亞,沒有靜態方法,沒有靜態屬性。

他們可以亞型

假設我們的Color類有一個lighter()方法,該方法應該將顏色轉移到下一個可用的打火機上:

class Color {protected final int hex;Color(int h) {this.hex = h;}public Color lighter() {return new Color(hex + 0x111);} }

但是,有時更希望通過一組可用的Pantone顏色選擇下一種較淺的顏色:

class PantoneColor extends Color {private final PantoneName pantone;PantoneColor(String name) {this(new PantoneName(name));}PantoneColor(PantoneName name) {this.pantone = name;}@Overridepublic Color lighter() {return new PantoneColor(this.pantone.up());} }

然后,我們創建一個靜態工廠方法,該方法將決定哪種Color實現最適合我們:

class Color {private final String code;static Color make(int h) {if (h == 0xBF1932) {return new PantoneColor("19-1664 TPX");}return new RGBColor(h);} }

如果要求使用真正的紅色 ,我們將返回PantoneColor一個實例。 在其他所有情況下,它只是一個標準的RGBColor 。 該決定是通過靜態工廠方法做出的。 這就是我們所說的:

Color color = Color.make(0xBF1932);

由于構造函數只能返回在其中聲明的類,因此不可能對構造函數進行相同的“分叉”。靜態方法具有返回Color任何子類型的所有必要自由。

真正。

但是,在面向對象的世界中,我們可以而且必須以不同的方式去做。 首先,我們將Color為接口:

interface Color {Color lighter(); }

接下來,我們將將此決策過程移至其自己的類Colors ,就像在上一個示例中所做的那樣:

class Colors {Color make(int h) {if (h == 0xBF1932) {return new PantoneColor("19-1664-TPX");}return new RGBColor(h);} }

而且我們將使用Colors類的實例,而不是Color內部的靜態方法:

colors.make(0xBF1932);

但是,這仍然不是真正的面向對象的思維方式,因為我們正在將決策權從對象所屬的對象轉移開。 通過靜態工廠方法make()或新類Colors實際上并不重要),我們將對象分成兩部分。 第一部分是對象本身,第二部分是決策算法,它位于其他地方。

更加面向對象的設計是將邏輯放入PantoneColor類的對象中,該對象將裝飾原始的RGBColor :

class PantoneColor {private final Color origin;PantoneColor(Color color) {this.origin = color;}@Overridepublic Color lighter() {final Color next;if (this.origin.hex() == 0xBF1932) {next = new RGBColor(0xD12631);} else {next = this.origin.lighter();}return new PantoneColor(next);} )

然后,我們創建一個RGBColor實例,并使用PantoneColor裝飾它:

Color red = new PantoneColor(new RGBColor(0xBF1932) );

我們要求red返回較淺的顏色,它返回Pantone調色板中的一種,而不是僅在RGB坐標中較淺的顏色:

Color lighter = red.lighter(); // 0xD12631

當然,這個示例是原始的,如果我們真的希望它適用于所有Pantone顏色,則需要進一步改進 ,但是我希望您能理解。 邏輯必須保留在類內部 ,而不是外部,靜態工廠方法甚至其他補充類中。 當然,我在說的是屬于這個特定類的邏輯。 如果與類實例的管理有關,那么可以有容器和存儲,就像上面的上一個示例一樣。

總而言之,我強烈建議您不要使用靜態方法,尤其是當它們要替換對象構造函數時。 通過其構造函數生成對象是任何面向對象軟件中最 “神圣”的時刻,請不要錯過它的美麗。

您可能還會發現這些相關的帖子很有趣: 每個私有靜態方法都是新類的候選人 ; 您是一個更好的建筑師,您的圖表更簡單 ; 只有一個主要的建設者 ; 為什么InputStream設計錯誤 ; 為什么在OOP中很多退貨聲明是個壞主意 ;

翻譯自: https://www.javacodegeeks.com/2017/11/constructors-static-factory-methods.html

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的构造函数还是静态工厂方法?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。