設計模式 - 工廠方法模式

f1uLove發表於2018-10-28

定義

  • 工廠方法模式是類的建立模式,又叫虛擬構造器(Virtual Constructor)模式,或者多型性工廠模式。
  • 定義一個建立物件的介面,讓子類決定例項化哪一個類。工廠方法使一個類的例項化延遲到其子類。

結構

工廠方法

工廠方法包含了一下角色

  • Product:抽象產品
  • ConcreteProduct:具象產品
  • Factory:抽象工廠
  • ConcreteFactory:具象工廠

場景示例

還是拿售賣機票舉例,我們之前用簡單工廠實現了不同供應商的下單邏輯,但是隨著業務的不斷擴大,我們對接的供應商越來越多,這樣就會造成每次對接一個供應商都會在工廠類中新增分支,對工廠類進行修改,這就違反了開閉原則,所以現在我們用工廠方法來修改一下。 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 程式碼

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:下單操作 以上就是一個簡單的工廠方法的實現。即使在新增新的供應商,我們只要建立新的供應商工廠以及其實現就可以了,這樣對我們的整個的工廠和產品體系都沒有發生修改,而只是擴充套件了變化,這就完全符合了開放-閉合原則。如果我們的需求發生了變化,要同時支援單程、往返的下單,只要我們在每一個供應商作為一個簡單工廠,建立出支援單程、往返的兩種具象的產品就可以了。但是我們仔細觀察就能發現,工廠方法模式實現時,客戶端需要決定例項化哪一個工廠,選擇判斷的問題還是存在的,也就是說,工廠方法把簡單工廠的內部邏輯判斷移到了客戶端程式碼來執行,你想要什麼功能,本來是去修改工廠的,但是現在是去修改了客戶端!

此例只是針對每個工廠只生成一個具象產品類,至於一個工廠生成多個具象產品類可將每個工廠改造成簡單工廠,具體可參考披薩店。 消除分支判斷可以利用反射的方法。(將在抽象工廠章節統一列出)

優點

  • 在工廠方法模式中,工廠方法用來建立客戶端需要的產品,同時還向客戶端隱藏了哪種具體產品類將被例項化這一細節,客戶端只用關心產品對應的工廠,無需關心建立細節,甚至無需知道具體產品的類名。

  • 面向介面程式設計,基於工廠角色和產品角色的多型性設計是工廠方法模式的關鍵。它能夠使工廠可以自主確定建立何種產品物件,而如何建立這個物件的細節則完全封裝在具體工廠內部。工廠方法模式之所以又被稱為多型工廠模式,是因為所有的具體工廠類都具有同一抽象父類。

  • 遵循開放-閉合原則,在系統中新增加一個產品時,不用更改抽象工廠以及抽象產品,也不用對客戶端以及具象工廠和產品做修改,而只要新增一個具體工廠和具體產品就可以了。

缺點

  • 在新增新產品時,需要編寫新的具體產品類,而且還要提供與之對應的具體工廠類,系統中類的個數將成對增加,在一定程度上增加了系統的複雜度,有更多的類需要編譯和執行,會給系統帶來一些額外的開銷。

  • 由於考慮到系統的可擴充套件性,需要引入抽象層,在客戶端程式碼中均使用抽象層進行定義,增加了系統的抽象性和理解難度,且在實現時可能需要用到DOM、反射等技術,增加了系統的實現難度。

應用場景

  • 一個類不知道它所需要的物件的類:在工廠方法模式中,客戶端不需要知道具體產品類的類名,只需要知道所對應的工廠即可,具體的產品物件由具體工廠類建立;客戶端需要知道建立具體產品的工廠類。

  • 一個類通過其子類來指定建立哪個物件:在工廠方法模式中,對於抽象工廠類只需要提供一個建立產品的介面,而由其子類來確定具體要建立的物件,利用物件導向的多型性和里氏代換原則,在程式執行時,子類物件將覆蓋父類物件,從而使得系統更容易擴充套件。

  • 將建立物件的任務委託給多個工廠子類中的某一個,客戶端在使用時可以無須關心是哪一個工廠子類建立產品子類,需要時再動態指定,可將具體工廠類的類名儲存在配置檔案或資料庫中。

擴充套件

  • 使用多個工廠方法,可在抽象工廠中定義多個工廠方法,從而使具體工廠實現不同的工廠方法,哲學工廠方法包含不同的邏輯,建立不同的產品(抽象工廠)
  • 產品物件的重複使用: (1)工廠物件將已經建立過的產品儲存到一個集合(如陣列、List等)中,然後根據客戶對產品的請求,對集合進行查詢。如果有滿足要求的產品物件,就直接將該產品返回客戶端;如果集合中沒有這樣的產品物件,那麼就建立一個新的滿足要求的產品物件,然後將這個物件在增加到集合中,再返回給客戶端。 (2)Spring單例模式的使用
  • 多型性的喪失和模式的退化:如果工廠僅僅返回一個具體產品物件,便違背了工廠方法的用意,發生退化,此時就不再是工廠方法模式了。一般來說,工廠物件應當有一個抽象的父型別,如果工廠等級結構中只有一個具體工廠類的話,抽象工廠就可以省略,也將發生了退化。當只有一個具體工廠,在具體工廠中可以建立所有的產品物件,並且工廠方法設計為靜態方法時,工廠方法模式就退化成簡單工廠模式。(本例就可以簡化為簡單工廠模式)

總結

  • 工廠方法模式又稱為工廠模式虛擬構造器模式。工廠方法中父類負責定義建立產品的統一介面,工廠子類負責生成具體的產品類。將產品的例項化操作延遲到子類進行,由子類決定例項化哪一個具體的產品類。

  • 工廠方法模式包含四個角色:抽象工廠具象工廠抽象產品具象產品

  • 工廠方法模式是簡單工廠的進一步的抽象和推廣,它們都是集中封裝了物件的建立,使得更換物件時不需要做大的改動就可以實現,降低了客戶端程式與產品物件的耦合。但是由於工廠方法模式使用了多型性,工廠方法模式保持了簡單工廠模式的有點,而且克服了它的缺點。

  • 工廠方法模式的主要優點是增加新的產品類時無須修改現有系統,並封裝了產品物件的建立細節,系統具有良好的靈活性和可擴充套件性;其缺點在於增加新產品的同時需要增加新的工廠,導致系統類的個數成對增加,在一定程度上增加了系統的複雜性。

  • 工廠方法模式適用情況包括:一個類不知道它所需要的物件的類;一個類通過其子類來指定建立哪個物件;將建立物件的任務委託給多個工廠子類中的某一個,客戶端在使用時可以無須關心是哪一個工廠子類建立產品子類,需要時再動態指定。

相關文章