天道不一定酬所有勤
但是,天道只酬勤

設計模式(五)——工廠方法模式

新專題:設計模式,我會在博客(http://www.057299.live)及微信公眾號(hollischuang)同步更新,歡迎共同學習。

設計模式(四)——簡單工廠模式文章中介紹了簡單工廠模式,通過一個例子講述了如何使用簡單工廠模式。同時也留下了一個問題,那就是簡單工廠模式破壞了開放-封閉原則。那么本文將介紹另外一種設計模式——工廠方法模式。主要介紹其概念、用途、實現方式、以及優缺點等。

概念

工廠方法模式(Factory Method Pattern)又稱為工廠模式,也叫虛擬構造器(Virtual Constructor)模式或者多態工廠(Polymorphic Factory)模式,它屬于類創建型模式。

工廠方法模式是一種實現了“工廠”概念的面向對象設計模式。就像其他創建型模式一樣,它也是處理在不指定對象具體類型的情況下創建對象的問題。

工廠方法模式的實質是“定義一個創建對象的接口,但讓實現這個接口的類來決定實例化哪個類。工廠方法讓類的實例化推遲到子類中進行?!?/p>

用途

工廠方法模式和簡單工廠模式雖然都是通過工廠來創建對象,他們之間最大的不同是——工廠方法模式在設計上完全完全符合“開閉原則”。

在以下情況下可以使用工廠方法模式:

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

一個類通過其子類來指定創建哪個對象:在工廠方法模式中,對于抽象工廠類只需要提供一個創建產品的接口,而由其子類來確定具體要創建的對象,利用面向對象的多態性和里氏代換原則,在程序運行時,子類對象將覆蓋父類對象,從而使得系統更容易擴展。

將創建對象的任務委托給多個工廠子類中的某一個,客戶端在使用時可以無須關心是哪一個工廠子類創建產品子類,需要時再動態指定,可將具體工廠類的類名存儲在配置文件或數據庫中。

實現方式

工廠方法模式包含如下角色:

Product:抽象產品(Operation

ConcreteProduct:具體產品(OperationAdd)

Factory:抽象工廠(IFactory)

ConcreteFactory:具體工廠(AddFactory)

QQ20160412-0

這里還用計算器的例子。在保持Operation,OperationAdd,OperationDiv,OperationSub,OperationMul等幾個方法不變的情況下,修改簡單工廠模式中的工廠類(OperationFactory)。替代原有的那個”萬能”的大工廠類,這里使用工廠方法來代替:

//工廠接口
public interface IFactory {
    Operation CreateOption();
}

//加法類工廠
public class AddFactory implements IFactory {

    public Operation CreateOption() {
        return new OperationAdd();
    }
}

//除法類工廠
public class DivFactory implements IFactory {

    public Operation CreateOption() {
        return new OperationDiv();
    }
}

//除法類工廠
public class MulFactory implements IFactory {

    public Operation CreateOption() {
        return new OperationMul();
    }
}

//減法類工廠
public class SubFactory implements IFactory {

    public Operation CreateOption() {
        return new OperationSub();
    }
}

這樣,在客戶端中想要執行加法運算時,需要以下方式:

public class Main {

    public static void main(String[] args) {
        IFactory factory = new AddFactory();
        Operation operationAdd =  factory.CreateOption();
        operationAdd.setValue1(10);
        operationAdd.setValue2(5);
        System.out.println(operationAdd.getResult());
    }
}

到這里,一個工廠方法模式就已經寫好了。


從代碼量上看,這種工廠方法模式比簡單工廠方法模式更加復雜。針對不同的操作(Operation)類都有對應的工廠。很多人會有以下疑問:

貌似工廠方法模式比簡單工廠模式要復雜的多?

工廠方法模式和我自己創建對象沒什么區別?為什么要多搞出一些工廠來?

下面就針對以上兩個問題來深入理解一下工廠方法模式。

工廠方法模式的利與弊

為什么要使用工廠來創建對象?

封裝對象的創建過程

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

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

為什么每種對象要單獨有一個工廠?

符合『開放-封閉原則

主要目的是為了解耦。在系統中加入新產品時,無須修改抽象工廠和抽象產品提供的接口,無須修改客戶端,也無須修改其他的具體工廠和具體產品,而只要添加一個具體工廠和具體產品就可以了。這樣,系統的可擴展性也就變得非常好,完全符合“開閉原則”。

以上就是工廠方法模式的優點。但是,工廠模式也有一些不盡如人意的地方:

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

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

工廠方法與簡單工廠的區別

工廠模式克服了簡單工廠模式違背開放-封閉原則的缺點,又保持了封裝對象創建過程的優點。

他們都是集中封裝了對象的創建,使得要更換對象時,不需要做大的改動就可實現,降低了客戶端與產品對象的耦合。

總結

工廠方法模式是簡單工廠模式的進一步抽象和推廣。

由于使用了面向對象的多態性,工廠方法模式保持了簡單工廠模式的優點,而且克服了它的缺點。

在工廠方法模式中,核心的工廠類不再負責所有產品的創建,而是將具體創建工作交給子類去做。這個核心類僅僅負責給出具體工廠必須實現的接口,而不負責產品類被實例化這種細節,這使得工廠方法模式可以允許系統在不修改工廠角色的情況下引進新產品。

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

文中所有代碼見GitHub

參考資料

大話設計模式

深入淺出設計模式

工廠方法模式(Factory Method Pattern)

(全文完) 歡迎關注『Java之道』微信公眾號
贊(1)
如未加特殊說明,此網站文章均為原創,轉載必須注明出處。HollisChuang's Blog » 設計模式(五)——工廠方法模式
分享到: 更多 (0)

評論 3

  • 昵稱 (必填)
  • 郵箱 (必填)
  • 網址
  1. #1

    不錯 不錯[/強]

    kuye4年前 (2016-07-21)回復
  2. #2

    umL 圖有錯誤嗎 ? 實現接口不是用 虛線的 三角形表示嗎? 文中用實線表示,應該是繼承關系

    稀里糊涂4年前 (2016-07-28)回復
  3. #3

    工廠方法怎么能不修改客戶端呢?新增一個工廠,你不得new這個工廠嗎?

    明。。。10個月前 (06-03)回復

HollisChuang's Blog

聯系我關于我
大乐透复式返奖 刘伯温自选一肖 单双中特免费公开 循环码的全部码组怎么求 六台宝典免费资料彩图 369爆平特平码 捕鸟达人千炮版 双色球20元复式打法 安徽11选5走势图真准网 四肖三期必开 捕鸟达人内购破解