工廠方法包含了一下角色數據庫
仍是拿售賣機票舉例,咱們以前用簡單工廠實現了不一樣供應商的下單邏輯,可是隨着業務的不斷擴大,咱們對接的供應商愈來愈多,這樣就會形成每次對接一個供應商都會在工廠類中添加分支,對工廠類進行修改,這就違反了開閉原則
,因此如今咱們用工廠方法來修改一下。 Factory 代碼編程
public interface Factory {
Product createProduct();
}
public class AFactory implements Factory {
@Override
public Product createProduct() {
return new AProduct();
}
}
public class BFactory implements Factory {
@Override
public Product createProduct() {
return new BProduct();
}
}
public class CFactory implements Factory {
@Override
public Product createProduct() {
return new CProdut();
}
}
... D
... E
複製代碼
Product代碼數組
public interface Product {
void createOrder();
}
public class AProduct implements Product {
@Override
public void createOrder() {
System.out.println("供應商A:下單操做");
}
}
public class BProduct implements Product {
@Override
public void createOrder() {
System.out.println("供應商B:下單操做");
}
}
public class CProdut implements Product {
@Override
public void createOrder() {
System.out.println("供應商B:下單操做");
}
}
... D
... E
複製代碼
Client 代碼bash
public class Client {
public static void main(String[] args) {
Factory aFactory = new AFactory();
Product aProduct = aFactory.createProduct();
aProduct.createOrder();
Factory bFactory = new BFactory();
Product bProduct = bFactory.createProduct();
bProduct.createOrder();
}
}
複製代碼
輸出供應商A:下單操做 供應商B:下單操做
以上就是一個簡單的工廠方法的實現。即便在添加新的供應商,咱們只要建立新的供應商工廠以及其實現就能夠了,這樣對咱們的整個的工廠和產品體系都沒有發生修改,而只是擴展了變化,這就徹底符合了開放-閉合
原則。若是咱們的需求發生了變化,要同時支持單程、往返的下單,只要咱們在每個供應商做爲一個簡單工廠,建立出支持單程、往返的兩種具象的產品就能夠了。可是咱們仔細觀察就能發現,工廠方法模式實現時,客戶端須要決定實例化哪個工廠,選擇判斷的問題仍是存在的,也就是說,工廠方法把簡單工廠的內部邏輯判斷移到了客戶端代碼來運行,你想要什麼功能,原本是去修改工廠的,可是如今是去修改了客戶端!ide
此例只是針對每一個工廠只生成一個具象產品類,至於一個工廠生成多個具象產品類可將每一個工廠改形成簡單工廠,具體可參考
披薩店
。 消除分支判斷能夠利用反射
的方法。(將在抽象工廠章節統一列出)ui
在工廠方法模式中,工廠方法用來建立客戶端須要的產品,同時還向客戶端隱藏了哪一種具體產品類將被實例化這一細節,客戶端只用關心產品對應的工廠,無需關心建立細節,甚至無需知道具體產品的類名。spa
面向接口編程
,基於工廠角色和產品角色的多態性設計是工廠方法模式的關鍵。它可以使工廠能夠自主肯定建立何種產品對象,而如何建立這個對象的細節則徹底封裝在具體工廠內部。工廠方法模式之因此又被稱爲多態工廠模式,是由於全部的具體工廠類都具備同一抽象父類。設計
遵循開放-閉合
原則,在系統中新增長一個產品時,不用更改抽象工廠以及抽象產品,也不用對客戶端以及具象工廠和產品作修改,而只要添加一個具體工廠和具體產品就能夠了。code
在添加新產品時,須要編寫新的具體產品類,並且還要提供與之對應的具體工廠類,系統中類的個數將成對增長,在必定程度上增長了系統的複雜度,有更多的類須要編譯和運行,會給系統帶來一些額外的開銷。cdn
因爲考慮到系統的可擴展性,須要引入抽象層,在客戶端代碼中均使用抽象層進行定義,增長了系統的抽象性和理解難度,且在實現時可能須要用到DOM、反射等技術,增長了系統的實現難度。
一個類不知道它所須要的對象的類:在工廠方法模式中,客戶端不須要知道具體產品類的類名,只須要知道所對應的工廠便可,具體的產品對象由具體工廠類建立;客戶端須要知道建立具體產品的工廠類。
一個類經過其子類來指定建立哪一個對象:在工廠方法模式中,對於抽象工廠類只須要提供一個建立產品的接口,而由其子類來肯定具體要建立的對象,利用面向對象的多態性和里氏代換原則,在程序運行時,子類對象將覆蓋父類對象,從而使得系統更容易擴展。
將建立對象的任務委託給多個工廠子類中的某一個,客戶端在使用時能夠無須關心是哪個工廠子類建立產品子類,須要時再動態指定,可將具體工廠類的類名存儲在配置文件或數據庫中。
擴展
- 使用多個工廠方法,可在抽象工廠中定義多個工廠方法,從而使具體工廠實現不一樣的工廠方法,哲學工廠方法包含不一樣的邏輯,建立不一樣的產品(抽象工廠)
- 產品對象的重複使用: (1)工廠對象將已經建立過的產品保存到一個集合(如數組、List等)中,而後根據客戶對產品的請求,對集合進行查詢。若是有知足要求的產品對象,就直接將該產品返回客戶端;若是集合中沒有這樣的產品對象,那麼就建立一個新的知足要求的產品對象,而後將這個對象在增長到集合中,再返回給客戶端。 (2)Spring單例模式的使用
- 多態性的喪失和模式的退化:若是工廠僅僅返回一個具體產品對象,便違背了工廠方法的用意,發生退化,此時就再也不是工廠方法模式了。通常來講,工廠對象應當有一個抽象的父類型,若是工廠等級結構中只有一個具體工廠類的話,抽象工廠就能夠省略,也將發生了退化。當只有一個具體工廠,在具體工廠中能夠建立全部的產品對象,而且工廠方法設計爲靜態方法時,工廠方法模式就退化成簡單工廠模式。(本例就能夠簡化爲簡單工廠模式)
工廠方法模式又稱爲工廠模式
,虛擬構造器
模式。工廠方法中父類負責定義建立產品的統一接口,工廠子類負責生成具體的產品類。將產品的實例化操做延遲到子類進行,由子類決定實例化哪個具體的產品類。
工廠方法模式包含四個角色:抽象工廠、具象工廠、抽象產品、具象產品
工廠方法模式是簡單工廠的進一步的抽象和推廣,它們都是集中封裝了對象的建立,使得更換對象時不須要作大的改動就能夠實現,下降了客戶端程序與產品對象的耦合。可是因爲工廠方法模式使用了多態性,工廠方法模式保持了簡單工廠模式的有點,並且克服了它的缺點。
工廠方法模式的主要優勢是增長新的產品類時無須修改現有系統,並封裝了產品對象的建立細節,系統具備良好的靈活性和可擴展性;其缺點在於增長新產品的同時須要增長新的工廠,致使系統類的個數成對增長,在必定程度上增長了系統的複雜性。
工廠方法模式適用狀況包括:一個類不知道它所須要的對象的類;一個類經過其子類來指定建立哪一個對象;將建立對象的任務委託給多個工廠子類中的某一個,客戶端在使用時能夠無須關心是哪個工廠子類建立產品子類,須要時再動態指定。