天天看點

高效Java01:考慮使用靜态工廠方法代替構造方法靜态工廠方法優勢一:它們擁有不同的自定義名稱靜态工廠方法優勢二:調用時無需重複建立新對象靜态工廠方法優勢三:它們可以傳回類型的任何子類型的對象靜态工廠方法優勢四:建立泛型執行個體的時候,它們使代碼更加簡潔(JDK1.7以後就不算優勢了)

Java中的每一個類被建立,大部分場景中用戶端都需要擷取它自身的一個執行個體然後進行使用,我們最常用的是為它提供一個公有的構造方法,除此之外還可以使用靜态工廠方法傳回它的一個執行個體。相較于構造方法,靜态工廠方法擁有以下好處:

  • 它們擁有不同的自定義名稱
  • 調用它時無需重複建立新對象
  • 它們可以傳回類型的任何子類型的對象
  • 建立參數化類型執行個體的時候,它們使代碼更加簡潔(JDK1.7以後就不算優勢了)

靜态工廠方法優勢一:它們擁有不同的自定義名稱

如果構造方法中的參數不能準确的表述會傳回什麼對象,那麼具有适當名稱的靜态工廠方法則更容易使用,産生的用戶端代碼也更易于了解。

例如有如下構造方法:

Person(String, int, String)
           

傳回的Person即可能為男人,也可能為女人,當然我們可以建立多個構造方法來解決這個問題,但随着構造方法的增多,使用者很難确定使用哪個構造方法,特别是在參考文檔卻是的情況下。

如果使用靜态工廠方法

Person.male

建立男人對象,使用

Person.female

建立女人對象則更準确。

靜态工廠方法優勢二:調用時無需重複建立新對象

調用構造方法每次都會建立一個新的執行個體對象,而有些場景中我們需要控制執行個體數或者基于性能考慮不能總是重新建立對象,這個時候,可以使用預先初始化執行個體對象,将其緩存起來,用到的時候直接傳回即可。如JDK中的Boolean.valueOf(boolean)方法:

public final class Boolean implements java.io.Serializable, Comparable<Boolean>
{
    public static final Boolean TRUE = new Boolean(true);

    public static final Boolean FALSE = new Boolean(false);

     public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
    }
}
           

其中

TRUE

FALSE

均為預先初始化的執行個體,靜态工廠方法僅進行直接傳回已緩存的對象。

靜态工廠方法優勢三:它們可以傳回類型的任何子類型的對象

我們先看一段示例代碼:

public interface Service {
}
public interface Provider {
    Service newService();
}
public class Services {
    private Services() {}

    private static final Map<String, Provider> providers = new ConcurrentHashMap<String, Provider>();
    public static final String DEFAULT_PROVIDER_NAME = "<def>";

    public static void registerDefaultProvider(Provider p) {
        registerProvider(DEFAULT_PROVIDER_NAME, p);
    }

    public static void registerProvider(String name, Provider p) {
        providers.put(name, p);
    }

    public static Service newInstance() {
        return newInstance(DEFAULT_PROVIDER_NAME);
    }

    public static Service newInstance(String name) {
        Provider p = providers.get(name);
        if (p == null)
            throw new IllegalArgumentException("No provider registered with name: " + name);
        return p.newService();
    }
}
           

上面的代碼中,接口

Provider

會有多個實作類,而每個實作類中的

newService()

方法均會傳回接口

Service

實作類的具體執行個體化對象,比如在業務場景busA下,需要使用名稱為

busAProvider

Provider

提供具體服務執行個體,我們僅需調用

Services.newInstance("busAProvider")

即可獲得對應的服務對象執行個體,而對于外部調用者,隻需要調用

Services.newInstance("String)

即可,調用

newInstance()

等同于

Services.newInstance("<def>")

靜态工廠方法優勢四:建立泛型執行個體的時候,它們使代碼更加簡潔(JDK1.7以後就不算優勢了)

在JDK1.7之前我們必須這樣執行個體化對象:

Map<String,List<Map<String,Objects>>> map = new HashMap<String,List<Map<String,Objects>>>();
           

類型參數越來越長,我們執行個體化對象時也必須指明,假設HashMap提供了一個靜态工廠方法:

public static <K, V> HashMap<K, V> newInstance(){
    return new HashMap<K, V>();
}
           

我們僅需這樣調用:

Map<String,List<Map<String,Objects>> map = HashMap.newInstance();
           

使用靜态工廠方法後,編譯器會自動幫我們找到對應的類型,這個功能叫做

類型推導

,JDK1.7新增了一個鑽石操作符

<>

實作了該功能,在1.7中我們可以使用它更簡單的完成泛型對象的執行個體化:

Map<String,List<Map<String,Objects>>> map = new HashMap<>();