設計模式(1) - 工廠方法

問題描述

一個接口(如下圖的Product)可能有多種實現方式。程序邏輯在實例化這種類型/接口的具體類(如下圖的ConcreteProduct)的時候,如果直接使用{new ConcreteProduct()}的方式來撰寫;當需求變更的時候,程序需要使用另外一個子類(例如SubProduct)來替換該類的時候,所有使用{new ConcreteProduct()}的地方都需要修改。這種代碼的特徵是:沒有封裝好程序的一個可能的“變化點”(即具體對象創建的可變性)。工廠方法模式把{new ClassName(...)}這種對象實例化的代碼封裝到一個相對穩定的Factory Method中,讓一個可能變化的邏輯(類如何實例化)對於客戶而言穩定不變。

工廠方法模式

如下圖所示,工廠方法模式爲具體對象(ConcreteProduct)的創建提供一個間接層,客戶端通過一個穩定的對象創建接口(即工廠方法: Product* ConcreteCreator::CreateProduct())來實例化該對象。當程序邏輯需要使用一個不同於ConcreteProduct的類來定義程序行爲時,只需要修改ConcreteCreator類的方法Product* ConcreteCreator::CreateProduct()的實現就可以了。雖然客戶端硬編碼了一個Factory Method類(即ConcreteCreator類),相對於到處修改{new ClassName(...)},這種硬編碼方式讓變化集中到了一個變化點,讓程序的修改侷限在一個可控的範圍。


討論

工廠方法模式的價值在於:

  • 封裝了程序一個可能的變化點:如何創建一個具體對象。本模式定義了一個對象創建的接口,客戶端使用這個接口來創建對象,保證了客戶端邏輯的穩定性
  • 解除了類的創建者(即類的客戶端邏輯)和具體類名字的耦合:不管接口如何子類化,修改ConcreteCreator的具體實現就可以創建不同的具體類
  • 強化了基於接口編程原則:工廠方法返回的通常是一個抽象類型(基類指針或者接口引用),這要求客戶端邏輯基於這些接口/抽象類型來構建,而不是基於具體類型

下面的代碼展示了MFC中使用本模式的一個例子:CreateObject()本質上就是一個工廠方法,可以創建一個不帶參數的,支持動態創建的MFC對象。雖然沒有抽象基類,但是已經體現了工廠方法模式的本質:通過一個穩定的接口來創建對象,返回一個抽象類型;讓對象的創建者和對象的具體類型解耦。

#define _DECLARE_DYNCREATE(class_name)     \
    _DECLARE_DYNAMIC(class_name)           \
    static CObject* PASCAL CreateObject();

#define IMPLEMENT_DYNCREATE(class_name, base_class_name)        \
    CObject* PASCAL class_name::CreateObject()                  \
        { return new class_name; }                              \
    IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \
        class_name::CreateObject)                               \
        ...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章