工廠方法模式:
定義:爲建立對象定義一個接口,讓子類決定實例化哪一個類。工廠方法讓一個類的實例化延遲至子類。
應用場景:
- 客戶類不關心使用哪一個具體類,只關心該接口所提供的功能;
- 建立過程比較複雜,例如須要初始化其餘關聯的資源類,讀取配置文件等;
- 接口有不少具體實現或者抽象有不少具體子類時,你可能須要爲客戶代碼寫一大串 if-else 邏輯來決定運行時使用哪一個具體實現或者具體子類;
- 不但願給客戶程序暴露過多此類的內部結構,隱藏這些細節能夠下降耦合度;
- 優化性能,好比緩存大對象或者初始化比較耗時的對象。
工廠方法模式:
//工廠接口定義了 createProduct()方法來放回 Product 類型的實例對象
public interface Factory {
// 若是具體實現較多,定義一個參數化的工廠方法,根據不一樣的參數返回不一樣的子類
Product createProduct(String type);
}
//工廠接口實現類
public class ConcreteFactory implements Factory {
// 若是具體實現較多,定義一個參數化的工廠方法,根據不一樣的參數返回不一樣的子類
@Override
public Product createProduct(String type) {
if ("type1".equals(type)) {
return new ConcreteProduct1();
} else if ("type2".equals(type)) {
return new ConcreteProduct2();
} else {
return new ConcreteProduct3();
}
}
}
//定義產品統一接口
public interface Product {
}
//不一樣的產品實現
public class ConcreteProduct1 implements Product {
}
public class ConcreteProduct2 implements Product {
}
public class ConcreteProduct3 implements Product {
}
客戶類經過工廠獲得產品實例:
public class Client {
private Factory factory;
public Client(Factory factory) {
this.factory = factory;
}
public void dosomething(String type) {
Product product = factory.createProduct(type);
// to do something
}
public static void main(String[] args) {
// 實例化工廠
Client client = new Client(new ConcreteFactory());
// 傳入參數給工廠獲得指定的產品實例
client.dosomething("type1");
}
}
靜態工廠方法:
應用場景:工廠模式爲每一個類建立一個工廠方法 方法類會引發工廠類的泛濫。
解決方案:使用靜態工廠方法來避免——在每一個類裏實現一個靜態的工廠方法,就再也不須要額外的工廠類。
靜態工廠方法的優缺點:
- 優勢:
- 能夠爲靜態工廠選擇合適的命名,提升程序的可讀性。
- 靜態工廠和工廠模式同樣,能夠封裝複雜的初始化過程,實現實例的緩存。
- 還能夠根據不一樣的輸入返回不一樣實現類/具體類對象。
- 缺點:
- 通常爲了強迫使用工廠方法,不直接使用構造方法來構造實例,咱們會強迫類只含有私有或是default的構造方法,這樣,會致使此類不能被子類化。
- 若是添加了一個新的該類的子類(該類有非私有的構造方法),此靜態工廠方法可能須要重寫,以加入該子類的實例化過程,致使擴展性不強。
- 靜態方法沒有面向對象的特徵,好比繼承、動態多態等,不可被覆寫(Overwritten)。
- 採用構造函數實例化對象,是語言的規範,而靜態工廠方法與其餘的靜態方法沒有區別,就增長了用戶使用的區別。但這能夠儘可能採用一些家喻戶曉的名字解決,讓用戶看到更名字就知道該方法是靜態工廠方法。如getInstance( )。
- 靜態工廠方法表明了一種對規範的背離。
建立類的實例最多見的是new 除此外還可使用靜態工廠方法,來封裝實例的細節,而且能控制實例的數量,減輕 jvm的堆棧中的壓力。
靜態工廠方法與用 new語句調用的構造方法相比,有如下區別:
- 使程序具備更好的可讀性。靜態工廠方法能夠突破構造函數不能自由命名的限制,對於不一樣的工廠方法能夠採用不一樣的會意的名字。JAVA平臺庫的java.text.Format的子類NumberFormat就有getInstance() , getPrecentInstance() , getCurrencyInstatnce()等靜態方法,經過不一樣的名字產生特定的對象。
- 加大了程序設計和使用的靈活行。靜態工廠方法是用來產生對象用的,至於產生什麼類型的對象沒有限制,這就意味這隻要返回原返回類型或原返回類型的子類型均可以;或者是否會建立一個新的對象徹底取決於方法的實現。如java.util集合框架就採用了這種優點,這樣就能夠更好達到封裝的目的,下降API的數目和用戶的使用難度,java.util.Connections是集合框架的輔助類用於對原有的集合類進行進一步封裝,產生一些同步的集合,不可修改的視圖。都是採用靜態工廠方法實現的,至於方法內部的實現類就徹底別封裝了。也迫使咱們使用接口編程。
- 解耦。靜態工廠方法所建立的對象能夠在編譯時不存在,動態建立對象,採用反射,相似Spring 的 IOC容器方轉。達到對象的建立與使用分離,使對象的客戶和對象之間解耦,增長程序的靈活性和可擴展性。
靜態工廠方法最主要的特色是:每次被調用的時候,不必定要建立一個新的對象。利用這一特色,靜態工廠方法可用來建立如下類的實例。
- 單例類:只有唯一的實例的類。
- 枚舉類:實例的數量有限的類。
- 具備實例緩存的類:能把已經建立的實例暫且存放在緩存中的類。
- 具備實例緩存的不可變類:不可變類的實例一旦建立,其屬性值就不會被改變。
所謂靜態工廠方法(static factory method),實際上只是一個簡單的靜態方法,它返回的是類的一個實例。
public static Boolean getTrue () {
return Boolean.TRUE;
}
總結:工廠模式把對象實例化的過程進行了封裝,客戶對象沒必要爲實例化而考慮更多,分離了實例化的邏輯,使得對象間的耦合性大大下降。