Java之靜態工廠方法
著名Java書籍《Effective Java》中第一條就提到了一個原則:考慮用靜態方法而不是構造器。初看這條規則的時候我還感到很費解,構造器是Java提供的構造物件的方法,為什麼不是首選呢?
假設有這樣一個類:
package com.example.demo; public class Dog { private String name; private String color; private int age; public Dog() { } public Dog(String name) { this.name = name; } public Dog(String name, String color, int age) { this.name = name; this.color = color; this.age = age; } }
一條狗的屬性很多,比如名字,顏色和年齡,我上面的類裡有三個構造器,一個無引數的預設構造器,一個引數只有name的構造器和一個有所有三個引數的構造器。
那麼這個時候問題來了,我想加一個只有毛色color引數的構造器,因為確實有些狗我只知道它的顏色,但是這已經是不可能了:
public Dog(String color) { this.color = color; }
方法過載也是有限制的,這個構造器實際上和name構造器衝突了。
為了實現功能,我們還是改改程式碼的好:
package com.example.demo; public class Dog { private String name; private String color; private int age; private Dog() { } public static Dog newDogWithAllParam(String name, String color, int age) { Dog dog = new Dog(); dog.name = name; dog.age = age; dog.color = color; return dog; } public static Dog newDogWithName(String name) { Dog dog = new Dog(); dog.name = name; return dog; } public static Dog newDogWithColor(String color) { Dog dog = new Dog(); dog.color = color; return dog; } // Getters & Setters }
每次新建物件的時候,只需要排程需要的方法就可以了。這段程式碼也解釋了書中提到的靜態工廠方法的一個好處——有名字。通過名字我可以清楚的知道我是用什麼屬性去建立的物件。
我個人很喜歡使用Guava的Lists類庫來建立List:
List<Long> list = Lists.newArrayList();
這種方式可以說簡潔而優雅,其實,這也是靜態工廠方法取代構造器的典型案例,它的原始碼可以來品味一下:
@GwtCompatible(serializable = true) public static <E> ArrayList<E> newArrayList() { return new ArrayList<>(); }
其實和我之前的程式碼原理上是一樣的。
《Effective Java》還提到了一條,就是靜態工廠方法不必在每次被呼叫的時候都會產生新物件,照例要看原始碼,我們看一下書裡提供的一段程式碼:
public static Boolean valueOf(boolean b) { return b ? Boolean.TRUE : Boolean.FALSE; }
在這樣的語句:boolean bl = Boolean.valueOf(false); 的時候,實際上是不需要建立額外的物件的,原因在我之前寫static的文章中有提及:
雖然上面的例子基本上是一句廢話,但是也能說明問題。
靜態工廠方法還有一個好處,就是可以返回子型別,比如我們有一個Car類,其中有一個關鍵的引數叫做price,我希望price>30萬的返回豪車子類,price<30萬的返回買菜車子類,那麼程式碼就要這樣寫了:
package com.example.demo; public class Car { private int price; Car() {} public static Car newCarWithPrice(int price) { if (price > 30 * 10000) { return new LuxCar(); } else { return new NormalCar(); } } }
這種程式碼就是構造器無法實現的了。