1. 程式人生 > 程式設計 >java 靜態工廠代替多參構造器的適用情況與優劣

java 靜態工廠代替多參構造器的適用情況與優劣

背景

假如現在你要想一個漢堡,有一個漢堡類:Hamburg。那麼一般情況下你會:

Hamburg hamburg = new Hamburg();

情景一:不同引數數目的構造器

製作漢堡可以選擇自定義,加肉,加菜,或者不新增,直接預設配方即可,那麼會有以下幾個構造器:

Hamburg();
Hamburg(Meat meat);
Hamburg(Meat meat,Vegetable vegetable);

當你要製作漢堡的時候,看到這麼多的構造器,但是卻不知道他們是什麼意思,返回的漢堡到底有什麼區別?查文件又有點麻煩,有沒有更好的解決方法呢?

情景二:不同種類的漢堡

如果有多種漢堡:新奧爾良漢堡,麥辣香漢堡。常規的做法就是:繼承漢堡類,實現子類,如:

class xinaoerliangHamburg extends Hamburg{}
class mailaHamburg extends Hamburg{}

但是會有問題:使用者在使用的時候,還得記住你那麼多類名,那是不是很麻煩?如果後續有更多的口味,那是不是要記住更多地類去才能得到對應的例項呢?有沒有更好的解決方法?

情景三:自定義漢堡的做法

如果漢堡的手法讓你非常不滿意,你想要用達芬奇技法來製作漢堡,那麼可以怎麼做呢?常規的做法是:

class Hamburg{
 ...
 //預設製作手法 
 private Maker mMaker = new DefaultMaker(); 
 public Hamburg(Maker maker){
  ...
  //使用傳進來的手法物件製作漢堡
  mMaker = maker;
  ...
 }
}

需要重新寫一個構造器,傳入引數來覆蓋原來的製作手法。這樣既有情景一的問題,還有另外的問題是:如果需要自定義的東西多的時候,那麼Hamburg裡需要維護的程式碼就更加的複雜了。

什麼是靜態工廠方法

以上情景問題可以通過靜態工廠方法來改善。

注意,這裡的靜態工廠方法並不是設計模式中的工廠模式。這裡只是使用靜態工廠方法來代替構造器例項化物件。

顧名思義,靜態工廠方法,就是使用靜態方法來構建類的例項,解決使用構造器例項化的各種問題。先看個例子,還是以上面的漢堡為例子,如果需要多種口味的漢堡,那麼可以:

class Hamburg{

 //獲取奧爾良口味的漢堡
 public static Hamburg ofAoErLiang(){
  return new AoErLiangHamburg();
 }
 //獲取麥辣香味的漢堡
 public static Hamburg ofMaiLaXiang(){
  return new MaiLaXiangHamburg();
 }
}

//兩種口味的漢堡,通過繼承漢堡實現
class AoErLiangHamburg extends Hamburg{}
class MaiLaXiangHamburg extends Hamburg{}

通過這種方法可以解決的是:使用者需要什麼型別的漢堡,可以直接通過Hamburg的靜態方法來獲取,而無需知道他的子類名字是什麼。而如果有更多種口味的漢堡,只需要擴充套件靜態方法即可;或者給靜態方法增加引數,通過switch來返回對應的口味漢堡。

靜態工廠優缺點

這裡的話會結合上面舉的例子,如果忘記了,看到可以返回去看一下。

優點

  • 解決構造器過載卻不知道各種構造器含義的問題。通過構造方法可以在方法名寫明,那麼使用者只需要通過方法名就知道這個方法是返回什麼物件。(例如情景一)例如:
//不同的靜態工廠方法返回不同的例項,通過方法名就知道他們的區別
//ps:這是android的動畫類
ObjectAnimator animator = ObjectAnimator.ofFloat();
ObjectAnimator animator = ObjectAnimator.ofInt();
  • 可以通過根據使用者的引數或者呼叫不同的靜態工廠方法來返回具體的子類物件。當後期要更換方法介面返回的子類時,對於使用者來說也是透明的,使用者只是拿到一個父類引用的物件。可以參考上面我在介紹靜態工廠方法舉的例子。

Java 8以上,可以在介面中定義靜態工廠方法,這樣無需知道該介面有多少個實現類,只需要根據靜態方法來獲取介面物件即可。

  • 重複利用物件,防止建立無用例項。這看起來很像單例,但是比單例要靈活得多。可以根據具體的情況,來判斷是否要快取例項。
  • 可以動態註冊程式碼。我們可以通過一組使用者註冊api,讓使用者先把需要的自定義程式碼注入,再呼叫靜態方法來獲取自己需要的物件型別。這樣的好處就是不會有一堆很複雜的構造器,內部邏輯也可以分離。對應情景三解決的問題

缺點

  1. 如果該類不包含public或者protect構造器,那麼將無法被子類例項化。因為我們想要使用者通過靜態方法來獲取物件,而不喜歡使用者通過構造方法來例項化物件。而如果把構造器設定為private,則無法被子類繼承。
  2. 無法在javadoc中直接檢視文件介紹,構造器是會直接生成doc的。但是直接通過方法名和引數名,已經可以看懂很多了。

靜態方法命名規範

方法名 含義
fromXxx 型別轉換
ofXxx 多個引數聚合
valueOf 和from of類似
getInstance 獲取一個例項,例項型別通過方法引數描述
getNewInstance/create 獲取一個新的例項
getType 主要用於工廠方法中獲取不同類的物件(屬於設計模式中的工廠方法)
newType 新建一個對應類的物件(屬於設計模式中的工廠方法)
type 上面兩者的簡化版

小結

在有多種子類或者過載構造器的時候,可以優先考慮一下靜態工廠方法,可以讓我們的程式碼更加地優雅,也方便我們進行維護。
另外這和設計模式中的工廠模式有區別,並不是一樣的,要進行區分。

參考資料

《effective java》

以上就是java 靜態工廠代替多參構造器的詳細內容,更多關於java 靜態工廠的資料請關注我們其它相關文章!