這是我參與8月更文挑戰的第4天,活動詳情查看:8月更文挑戰java
工廠模式
- 建立型模式:
- 對類的實例化過程進行抽象,可以將對象的建立和對象的使用分離開來
- 爲了使得軟件的結構更加清晰,外界對於這些對象使用只須要知道共同的接口,而不在乎具體實現的細節,這樣使得整個系統更加符合單一職責的原則
- 建立型模式隱藏了類的實例的建立細節,經過隱藏對象建立和組合過程從而使得整個系統相互獨立的目的
- 建立型模式在建立什麼,由誰建立,什麼時候建立更加靈活
- 工廠模式是一個重要的建立型模式,主要功能就是實例化對象
- 工廠模式: 負責將有共同接口的類實例化
- 主要解決接口選擇問題
- 在不一樣的條件下須要建立不一樣的實例時使用
- 工廠模式是一種建立型模式,提供了建立對象的最佳方式
- 使用工廠模式建立對象不會對客戶端暴露建立邏輯,而且使用一個共同的接口來指向新建立的對象
- 工廠模式在子類中實現工廠接口,建立過程在子類中執行
- 工廠模式的分類:
- 簡單工廠模式Simple Factory
- 工廠方法模式Factory Method
- 抽象工廠模式Abstract Factory
- 工廠模式優勢:
- 可使得代碼結構清晰,有效地封裝變化
- 對調用者屏蔽具體的產品類
- 下降代碼的耦合度
- 工廠模式的使用場景:
- 在任何須要生成複雜對象的地方,均可以使用工廠方法模式.只有複雜的對象才適用於工廠方法模式.對於簡單的只要經過new就能夠完成建立的對象,無需使用工廠模式.若是簡單對象使用工廠模式,須要引入一個工廠類,增長系統的複雜度
- 工廠模式是一種典型的解耦模式,當類之間須要增長依賴關係時,可使用工廠模式下降系統之間的耦合度
- 工廠模式是依靠抽象架構的,將實例化的任務交給子類實現,擴展性好.當系統須要較好的擴展性時,可使用工廠模式,不一樣的產品使用不一樣的工廠來實現組裝
簡單工廠模式
- 簡單工廠模式Simple Factory Pattern:
- 定義一個類用於負責建立其他類的實例,根據自變量的不一樣返回不一樣類的實例,被建立的實例一般都有一個共同的父類
- 簡單工廠模式中用於建立實例的方法時靜態static方法,所以又稱做是靜態工廠方法模式
- 簡單工廠模式的角色:
- 工廠類Factory : 簡單工廠模式核心類. 負責建立全部產品的內部邏輯,工廠類能夠被外部調用,建立所需對象
- 抽象產品類Product : 工廠類建立的全部對象的父類,封裝產品的共有方法.提升系統的靈活性.使得工廠類只須要定義一個通用的工廠方法,由於全部建立的具體產品都是這個子類對象
- 具體產品類ConcorrectProduct: 全部被建立的對象都是這個類的具體實例,須要實現抽象產品中聲明的抽象方法
- 簡單工廠模式代碼實現
- 簡單工廠模式優勢:
- 簡單工廠模式提供了專門的類用於建立對象,實現了對責任的分割. 工廠類Factory中含有必要的判斷邏輯,決定建立具體產品類ConcreteProduct的實例,客戶端只須要消費產品
- 客戶端不須要知道須要建立的具體產品類ConcreteProduct的類名,只須要知道具體產品類ConcreteProduct對應的參數便可
- 經過引入配置文件,能夠在不修改客戶端的狀況下修改和增長新的產品類ConcreteProduct, 提升了系統的靈活性
- 簡單工廠模式缺點:
- 工廠類Factory集中了全部產品的建立邏輯,若是發生異常,整個系統都會發生故障
- 簡單工廠模式中增長了系統中類的個數,增長了系統的複雜度和理解難度
- 簡單工廠模式中若是須要添加新的產品須要修改工廠邏輯,違背了開閉原則,不利於系統的擴展和維護
- 簡單工廠模式使用了靜態方法,沒法造成基於繼承的等級結構
- 簡單工廠模式的使用場景:
- 工廠類中負責建立的對象比較少時
- 客戶端只須要知道傳入工廠類的參數,不關心建立對象的參數
簡單工廠類的實現方式
直接傳入判斷參數key
public class Factory {
public static Product produce(String concreteProductType) {
switch (concreteProductType) {
case "A" :
return new ConcreteProductA();
break;
case "B" :
return new ConcreteProductB();
break;
default :
throw new Exception("沒有對應的產品類型");
break;
}
}
}
複製代碼
- 問題:
- 若是新增產品類,須要在工廠類中新增case
- 違背了開閉原則,這種方法是不建議使用的
利用反射
public Class Factory {
public static Product produce(String concreteProductClassPathName) throw Exception {
try {
Product product = (Product)Class.forName(concreteProductClassPathName).newInstance();
return product;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
throw new Exception("沒有對應的產品");
}
}
複製代碼
- 問題:
- 若是新增產品類,須要傳入具體產品類的類路徑名稱
- 能夠經過配置文件進行優化,將具體產品類的類路徑名稱配置在properties文件中,經過加載配置文件將類路徑名稱傳入工廠類的方法中
- 這樣新增產品類,只須要修改配置文件便可
反射和配置文件結合
A=com.oxford.factory.simple.ConcreteProductA
B= com.oxford.factory.simple.ConcreteProductB
複製代碼
- PropertyReader: 增長一個配置文件讀取類,將配置文件的信息讀取到Map中
public Class PropertyReader {
public static Map<String, String> property = new HashMap<>();
public Map<String, String> readProperty(String fileName) {
Properties properties = new Properties();
InputStream input = getClass.getResourceAsStream(fileName);
try {
pro.load(input);
Iterator<String> iterator = pro.StringPropertyNames().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
String value = properties.getProperty(key);
map.put(key, value);
}
input.close();
} catch (IOException e) {
e.printStacTrace();
}
return map;
}
}
複製代碼
public Class Factory {
public static Product produce(String concreteProductType) throws Exception {
PropertyReader reader = new PropertyReder();
Map<String, String> property = reader.readProperty("property.properties");
try {
Product product = (Product)Class.forName(property.get(concreteProductType)).newInstance();
return product;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
throw new Exception("沒有對應的產品");
}
}
複製代碼
- 問題:
- 每次調用的方法時,都要解析配置文件,增長系統開銷
- 能夠在文件讀取類在程序啓動時就加載,就能夠不用在每次調用時解析配置文件了
簡單工廠模式總結
- 工廠類是整個簡單工廠模式的關鍵:
- 工廠類中包含必要的判斷邏輯,根據給定的參數來決定建立哪個具體的產品類
- 經過使用工廠類,客戶端只須要消費具體產品便可,而不用關注具體產品對象的建立過程
- 經過使用簡單工廠模式明確了各個類的職責,有利於整個軟件體系結構的優化
- 工廠類中集中了全部具體對象的建立邏輯,違背了高內聚的責任分配原則.這樣工廠類中建立的類只能是事先考慮到的,若是須要添加新的類,則須要修改工廠類的邏輯,這違背了開閉原則
- 當系統中的具體產品類不斷增多時,就會出現要求工廠類根據不一樣的條件建立不一樣的實例的需求.這種對條件的判斷和對具體產品類型的判斷交錯在一塊兒,不利於對系統的擴展和維護.這樣的問題能夠經過使用工廠方法模式進行優化
工廠方法模式
- 工廠方法模式Factory Method Pattern:
- 定義一個建立對象的接口,經過實現這個接口的類來決定實例化具體的類
- 工廠方法模式讓具體的類的實例化延遲到子類中進行
- 工廠方法模式的角色:
- 工廠類Factory:
- 工廠方法接口,一般返回一個抽象產品類型Product的實例對象
- 這個類是工廠方法模式的核心,與客戶端程序無關. 任何在模式中建立的具體產品都須要實現這個接口
- 工廠實現類ConcreteFactory:
- 工廠類接口實現,覆寫工廠類Factory定義的工廠方法,返回具體產品類ConcreteProduct的抽象產品類型Product類型的實例
- 工廠實現類ConcreteFactory中包含與客戶端密切相關的邏輯,而且被客戶端調用來建立具體的產品實例
- 抽象產品類Product:
- 工廠方法模式建立的具體產品類的父類,定義類具體產品中共有的方法
- 具體產品類ConcreteProduct:
- 具體產品實現類,實現了抽象產品類Product中的方法
- 工廠模式建立的每個對象都是具體產品類ConcreteProduct的一個實例
- 工廠方法模式代碼實現
- 工廠方法模式優勢:
- 在工廠方法模式中,經過工廠方法來建立客戶端須要的產品ConcreteProduct, 用戶只須要關心須要具體產品ConcreteProduct對應的工廠實現ConcreteFactory. 不須要關心具體產品ConcreteProduct的建立細節和具體產品類ConcreteProduct的名稱
- 基於工廠類Factory和抽象產品類Product的多態性設計是工廠方法模式的關鍵. 這樣工廠類Factory能夠自主肯定須要建立何種產品ConcreteProduct的對象,而且建立具體產品ConcreteProduct對象的具體實現封裝在具體工廠ConcreteFactory的內部. 具體工廠類ConcreteFactory都具備同一父類接口Factory, 所以工廠方法模式又稱爲多態工廠模式
- 工廠方法模式徹底符合開閉原則,有利於系統的擴展和維護. 工廠方法模式在系統中添加新產品時,只須要添加一個具體工廠類ConcreteFactory和具體產品類ConcreteProduct便可
- 工廠方法模式缺點:
- 工廠模式在系統中添加新產品時,須要添加具體產品類ConcreteProduct和具體工廠類ConcreteFactory, 系統中類的個數成對增長,必定程度上增長了系統複雜度以及系統編譯運行的開銷
- 工廠方法模式的使用場景:
- 一個類不須要知道所須要的對象的類: 工廠方法模式中,客戶端不知道具體產品類的類名,只知道具體的產品對象由哪個具體工廠實現來建立. 這時,客戶端須要知道建立具體產品的具體工廠實現類
- 一個類經過子類來指定建立哪個對象: 工廠方法模式中,工廠類中只須要一個建立產品的的接口,由子類來肯定具體要建立的對象,經過利用多態和里氏代換原則,能夠在程序運行時,經過子類對象覆蓋父類對象,從而使得系統得以擴展
- 經過將建立具體產品的任務交由工廠類的具體工廠實現來完成,客戶端不須要關心具體產品類的建立, 須要的時候動態指定產品的具體工廠實現便可. 能夠將具體工廠類的類名存儲在配置文件或者數據庫中
- 工廠方法模式的使用場景示例:
- 日誌記錄器: 日誌能夠記錄到本地磁盤,系統事件,遠程服務器等等,用戶能夠選擇日誌記錄的位置
- 數據庫訪問: 當用戶不知道最後系統採用哪一類數據庫時,以及數據庫可能會發生變化時
- 服務器框架設計: 設計一個鏈接服務器的框架時,可能會用到三個協議POP3, IMAP, HTTP時,能夠將三個協議看做是具體產品類,使用工廠方法模式實現
工廠方法模式總結
- 工廠方法模式是簡單工廠模式的抽象和拓展,經過多態,工廠方法模式保持了簡單工廠模式的優勢,改善了簡單工廠模式的缺點
- 工廠方法模式中,核心的工廠類僅僅給出具體工廠實現必須實現的接口,再也不負責具體產品的建立,具體產品的建立交由具體的工廠實現完成.這樣使得系統能夠在不修改核心的工廠類時進行具體產品實現的擴展
- 優勢:
- 客戶端想要建立對象,只須要知道具體工廠實現便可
- 系統的擴展性高,若是新增產品,只須要一個具體工廠實現類和具體產品類便可,符合開閉原則
- 對客戶端隱藏了具體實現,客戶端只須要關心具體的工廠實現便可
- 缺點:
- 每次增長一個產品,都須要增長一個具體工廠實現類和具體產品類,這樣使得系統中類的個數成倍增長,在必定程度上增長了系統的複雜度,也增長了系統具體類的依賴,同時類的增長也增長了編譯和運行時的系統開銷
抽象工廠模式
- 抽象工廠模式Abstract Factory Pattern:
- 提供接口或者抽象類用於建立一組相關或者相互依賴的具體產品對象,不須要指定具體的類
- 抽象工廠模式的基本思想:
- 工廠方法模式經過引入工廠等級結構,解決了簡單工廠模式中工廠類的職責過大的問題.可是因爲工廠方法模式中每一個工廠只生產一類產品,這樣可能會致使存在大量的工廠類的問題,這樣會增長系統的開銷
- 能夠將一些相關的產品組成一個產品族,由同一個工廠來統一輩子產
- 產品族: 位於不一樣產品等級結構中功能相關聯的產品組成的家族
- 抽象工廠模式與工廠方法模式區別:
- 抽象工廠模式:
- 抽象工廠模式是針對多個產品的等級結構
- 抽象工廠模式的具體產品實現或者繼承於不一樣的接口或者抽象類
- 工廠方法模式:
- 工廠方法模式是針對一個產品的等級結構
- 工廠方法模式的具體產品實現或者繼承於同一個接口或者抽象類
- 抽象工廠模式的角色:
- 抽象工廠類AbstractFactory: 抽象工廠模式的核心,與應用的業務邏輯無關. 一般使用接口或者抽象類實現,全部具體工廠類ConcreteFactory必須實現接口或者抽象類
- 具體工廠類ConcreteFactory: 實現工廠定義的方法,包含建立具體產品實例的業務邏輯
- 抽象產品AbstractProduct: 定義一類產品對象的接口或者抽象類,這個類是工廠方法模式建立的對象的父類
- 具體產品ConcreteProduct: 實現業務邏輯的具體的產品,抽象工廠中建立的每個產品對象都是一個具體產品的實例
- 抽象工廠模式代碼實現
- 抽象工廠模式優勢:
- 抽象工廠模式分隔了具體類的生成,客戶端不須要知道具體建立的類
- 當一個產品族中的對象設計成一塊兒工做時,可以保證客戶端只使用同一個產品族的對象
- 抽象工廠模式缺點:
- 若是添加新的產品對象時,難以對產品等級結構進行擴展
- 抽象工廠模式的使用場景:
- 一個系統中不依賴於產品類的具體實例的建立,組合以及表達的細節
- 系統中有多個產品族,而且每次只使用其中一種產品族
- 同一個產品族的產品會在一塊兒使用
- 系統中提供一個產品類的庫,客戶端不依賴具體產品的實現,全部產品以一樣的接口出現
- 系統結構穩定,不會頻繁增長產品族
- 抽象工廠模式問題: 開閉原則的傾斜性
- 抽象工廠模式中開閉原則的傾斜性是指在抽象工廠模式中,增長新的產品方便,可是增長新的產品族很麻煩
- 開閉原則要求系統對修改關閉,對擴展開放.對於多個產品族和多個產品等級結構的系統的功能擴展加強包括:
- 增長產品: 對於增長新的產品,只須要增長一個對應的具體工廠便可,不須要修改已有的代碼
- 增長產品族: 對於增長新的產品族的產品等級結構,須要修改全部的工廠角色,包括抽象工廠類,在全部的工廠類中都須要增長生產新產品族產品的方法,這是違背了開閉原則的
- 由於抽象工廠模式存在開閉原則的傾斜性,所以要求在系統設計之初就要考慮整個系統的全部產品族,不會在設計完成以後再增長新的產品族,也不會刪除已有的產品族.不然會致使系統有大量的修改,難以維護
抽象工廠模式總結
- 抽象工廠模式是工廠方法模式的進一步拓展,提供了更爲強大的工廠類用於系統的擴展
- 抽象工廠模式分隔了具體類的生成,客戶端無需瞭解產品的建立過程,這樣使得很容易切換具體工廠.由於全部的具體工廠都實現了抽象工廠中定義的公共接口,所以只須要改變具體工廠的實例,就能夠改變整個系統的行爲
- 當一個產品族中的多個產品對象一塊兒工做時,能夠保證客戶端始終只使用同一個產品族中的對象
- 增長新的產品很方便,無需修改已有的系統,符合開閉原則
- 可是增長系統新的產品族的產品等級結構很麻煩,須要對原有的系統大量修改,甚至須要修改抽象層代碼,違背了開閉原則