天天看點

C++設計模式之Factory(工廠)模式

工廠模式一般是學習設計模式的第一課,它本身也是建立型模式中較為常用的一種模式.

工廠模式希望解決的是"如何高效而友善的建立目前需要的對象"的問題.當一個對象對外提供的接口穩定,而這類對象的具體實作容易發生變化時,我們可以考慮使用工廠來封裝對象的實作變化,并提供統一的對象建立方法.

工廠模式可以分為三種不同的模式,分别對應不同情況下的解決方案.

  • 1.簡單工廠模式

簡單工廠通過一個工廠類對象建立出所有的産品類.通過外部給予的條件參數,動态的建立出不同的産品類的執行個體.類圖如下:

C++設計模式之Factory(工廠)模式

示例代碼:

// 産品接口類
class IProduct abstract
{
public:
    virtual ~IProduct()
    {
    }
 
public:
    virtual void Func() = 0;
};
 
// 具體的産品類
 
class CAProduct : public IProduct
{
public:
    virtual void Func()
    {
        _tcout << _T("Product A") << endl;
    }
};
 
class CBProduct : public IProduct
{
public:
    virtual void Func()
    {
        _tcout << _T("Product B") << endl;
    }
};
 
class CCProduct : public IProduct
{
public:
    virtual void Func()
    {
        _tcout << _T("Product C") << endl;
    }
};
 
//
 
// 簡單工廠類
class CSimpleFactory
{
public:
    static TSmartPtr<IProduct> CreateProduct(const _tstring& str)
    {
        if( str == _T("A") )
            return new CAProduct;
        else if( str == _T("B") )
            return new CBProduct;
        else if( str == _T("C") )
            return new CCProduct;
        else
            return NULL;
    }
};
           

調用方式:

_tcout << _T("簡單工廠:") << endl;
// 利用簡單工廠建立産品
CSimpleFactory::CreateProduct(_T("A"))->Func();        // 建立産品A并調用
CSimpleFactory::CreateProduct(_T("B"))->Func();        // 建立産品B并調用
CSimpleFactory::CreateProduct(_T("C"))->Func();        // 建立産品C并調用
           

簡單工廠在所有工廠模式中實作上最為簡便,而且并不需要很多的工廠類,同時很好的将産品類的建立過程封裝,并解耦産品類實作與調用.

它最大的硬傷在于工廠類内部包含了所有具體産品類的建構.當我們需要增加某個産品類,或者修改某個産品類的建構方式時,我們就不得不修改工廠類.

下面的工廠方法模式可以解決這個問題.

  • 2.工廠方法模式

工廠方法模式通過一個工廠接口定義多個工廠類對象,将建立具體産品類的工作推遲到單獨的工廠子類當中,進而将具體的産品類建立過程與工廠類對象解耦.類圖如下:

C++設計模式之Factory(工廠)模式

示例代碼:

// 工廠接口類
class IFactory abstract
{
public:
    virtual TSmartPtr<IProduct> CreateProduct() = 0;
};
 
// 具體的工廠類
 
class CAFactory : public IFactory
{
public:
    virtual TSmartPtr<IProduct> CreateProduct()
    {
        return new CAProduct;
    }
};
 
class CBFactory : public IFactory
{
public:
    virtual TSmartPtr<IProduct> CreateProduct()
    {
        return new CBProduct;
    }
};
 
class CCFactory : public IFactory
{
public:
    virtual TSmartPtr<IProduct> CreateProduct()
    {
        return new CCProduct;
    }
};
           

調用方式:

_tcout << _T("工廠方法:") << endl;
TSmartPtr<IFactory> c_p_factory;
// 利用工廠方法建立産品
c_p_factory = new CAFactory;
c_p_factory->CreateProduct()->Func();            // 建立産品A并調用
c_p_factory = new CBFactory;
c_p_factory->CreateProduct()->Func();            // 建立産品B并調用
c_p_factory = new CCFactory;
c_p_factory->CreateProduct()->Func();            // 建立産品C并調用
           

可以看到,此時當我們需要增加一個新的産品時,隻需要增加一個對應的工廠類即可,不需要修改原來的任何代碼.

  • 3.抽象工廠模式

從上面的叙述中,我們似乎感覺問題已經比較完美的解決了,那麼抽象工廠與工廠方法相比又優化了哪些地方呢?

工廠方法可以針對同一系列産品接口提供同一系列的工廠類,但是若我們有多個産品系列,每個系列的接口各不相同,此時我們就需要定義多個工廠類系列,頗為不友善.

抽象工廠将各個産品系列的接口統一到一個工廠系列中,通過一個工廠類對象可以建立出所有系列的對應産品.類圖如下:

C++設計模式之Factory(工廠)模式

示例代碼:

//
 
// 産品接口類
 
class IProduct abstract
{
public:
    virtual ~IProduct()
    {
    }
 
public:
    virtual void Func() = 0;
};
 
class IProduct2 abstract
{
public:
    virtual ~IProduct2()
    {
    }
 
public:
    virtual void Func2() = 0;
};
 
//
 
// 具體的産品類
 
class CAProduct : public IProduct
{
public:
    virtual void Func()
    {
        _tcout << _T("Product A") << endl;
    }
};
 
class CBProduct : public IProduct
{
public:
    virtual void Func()
    {
        _tcout << _T("Product B") << endl;
    }
};
 
class CCProduct : public IProduct
{
public:
    virtual void Func()
    {
        _tcout << _T("Product C") << endl;
    }
};
 
// 具體的産品類2
 
class CAProduct2 : public IProduct2
{
public:
    virtual void Func2()
    {
        _tcout << _T("Product2 A") << endl;
    }
};
 
class CBProduct2 : public IProduct2
{
public:
    virtual void Func2()
    {
        _tcout << _T("Product2 B") << endl;
    }
};
 
class CCProduct2 : public IProduct2
{
public:
    virtual void Func2()
    {
        _tcout << _T("Product2 C") << endl;
    }
};
 
//
 
// 抽象工廠接口類
class IAbstractFactory abstract
{
public:
    virtual TSmartPtr<IProduct> CreateProduct() = 0;
    virtual TSmartPtr<IProduct2> CreateProduct2() = 0;
};
 
// 抽象工廠類
 
class CAFactory : public IAbstractFactory
{
public:
    virtual TSmartPtr<IProduct> CreateProduct()
    {
        return new CAProduct;
    }
 
    virtual TSmartPtr<IProduct2> CreateProduct2()
    {
        return new CAProduct2;
    }
};
 
class CBFactory : public IAbstractFactory
{
public:
    virtual TSmartPtr<IProduct> CreateProduct()
    {
        return new CBProduct;
    }
 
    virtual TSmartPtr<IProduct2> CreateProduct2()
    {
        return new CBProduct2;
    }
};
 
class CCFactory : public IAbstractFactory
{
public:
    virtual TSmartPtr<IProduct> CreateProduct()
    {
        return new CCProduct;
    }
 
    virtual TSmartPtr<IProduct2> CreateProduct2()
    {
        return new CCProduct2;
    }
};
           

調用方式:

_tcout << _T("抽象工廠:") << endl;
TSmartPtr<IAbstractFactory> c_p_factory;
// 利用抽象工廠建立産品
c_p_factory = new CAFactory;
c_p_factory->CreateProduct()->Func();                // 建立産品1A并調用
c_p_factory->CreateProduct2()->Func2();                // 建立産品2A并調用
c_p_factory = new CBFactory;
c_p_factory->CreateProduct()->Func();                // 建立産品1B并調用
c_p_factory->CreateProduct2()->Func2();                // 建立産品2B并調用
c_p_factory = new CCFactory;
c_p_factory->CreateProduct()->Func();                // 建立産品1C并調用
c_p_factory->CreateProduct2()->Func2();                // 建立産品2C并調用
           

我們可以看到,這種情況下如果我們采用工廠方法模式,肯定會出現大量的工廠類,讓我們在使用中非常的頭疼,維護起來也頗為麻煩.抽象工廠模式将同一種建構方法的不同産品族放入同一個工廠中處理,讓調用者可以更加專注于定位自己需要的産品,而不是去判斷各種令人眼花缭亂的工廠類.

在實際使用中,工廠方法和抽象工廠的使用都不是很多.原因是它們的工廠類都太多了,而且抽象工廠的外部接口邏輯也比較複雜.我們可以試試看用一個簡單工廠來解決上面抽象工廠的問題:

// 簡單工廠類
class CSimpleFactory
{
public:
    static TSmartPtr<IProduct> CreateProduct(const _tstring& str)
    {
        if( str == _T("A") )
            return new CAProduct;
        else if( str == _T("B") )
            return new CBProduct;
        else if( str == _T("C") )
            return new CCProduct;
        else
            return NULL;
    }
 
    static TSmartPtr<IProduct2> CreateProduct2(const _tstring& str)
    {
        if( str == _T("A") )
            return new CAProduct2;
        else if( str == _T("B") )
            return new CBProduct2;
        else if( str == _T("C") )
            return new CCProduct2;
        else
            return NULL;
    }
};
 
// ...
 
_tcout << _T("簡單工廠:") << endl;
// 利用簡單工廠建立産品
CSimpleFactory::CreateProduct(_T("A"))->Func();        // 建立産品1A并調用
CSimpleFactory::CreateProduct2(_T("A"))->Func2();    // 建立産品2A并調用
CSimpleFactory::CreateProduct(_T("B"))->Func();        // 建立産品1B并調用
CSimpleFactory::CreateProduct2(_T("B"))->Func2();    // 建立産品2B并調用
CSimpleFactory::CreateProduct(_T("C"))->Func();        // 建立産品1C并調用
CSimpleFactory::CreateProduct2(_T("C"))->Func2();    // 建立産品2C并調用
           

整個代碼簡潔明了,調用接口也很清晰.是以簡單工廠是工廠模式中最為實用的一種了.唯一麻煩的地方就在于維護工廠内部邏輯上.往往為了達到通用的處理接口,工廠内部實作不會使用switch-case或者if-else,而采用RTTI或者類似的機制來完成類的動态建立.此時的工廠就是一個非常有力的武器,既有簡單工廠的簡潔清晰,又有抽象工廠添加改寫的友善性.

運用好工廠模式,可以比較完美的解決多系列對象建立的需求變化,在使用之前必須将變化本身徹底封裝入産品類,并提取出固定不變的通用接口.可以說,工廠模式徹底诠釋了OOP面向接口程式設計的特征,融會貫通的用好了工廠模式,我們也就學會了如何将面向接口程式設計的思想代入到程式的其他需求實作中.

下面給出完整的示例代碼:

  • Factory_Method.cpp
//
// 工廠方法模式 C++示例
//
// Author:    木頭雲
// Blog:    http://darkc.at
// E-Mail:    [email protected]
// Version:    1.0.819.1550(2009/08/19)
//
 
#include "stdafx.h"
 
//
 
// 産品接口類
class IProduct abstract
{
public:
    virtual ~IProduct()
    {
    }
 
public:
    virtual void Func() = 0;
};
 
// 具體的産品類
 
class CAProduct : public IProduct
{
public:
    virtual void Func()
    {
        _tcout << _T("Product A") << endl;
    }
};
 
class CBProduct : public IProduct
{
public:
    virtual void Func()
    {
        _tcout << _T("Product B") << endl;
    }
};
 
class CCProduct : public IProduct
{
public:
    virtual void Func()
    {
        _tcout << _T("Product C") << endl;
    }
};
 
//
 
// 簡單工廠類
class CSimpleFactory
{
public:
    static TSmartPtr<IProduct> CreateProduct(const _tstring& str)
    {
        if( str == _T("A") )
            return new CAProduct;
        else if( str == _T("B") )
            return new CBProduct;
        else if( str == _T("C") )
            return new CCProduct;
        else
            return NULL;
    }
};
 
//
 
// 工廠接口類
class IFactory abstract
{
public:
    virtual TSmartPtr<IProduct> CreateProduct() = 0;
};
 
// 具體的工廠類
 
class CAFactory : public IFactory
{
public:
    virtual TSmartPtr<IProduct> CreateProduct()
    {
        return new CAProduct;
    }
};
 
class CBFactory : public IFactory
{
public:
    virtual TSmartPtr<IProduct> CreateProduct()
    {
        return new CBProduct;
    }
};
 
class CCFactory : public IFactory
{
public:
    virtual TSmartPtr<IProduct> CreateProduct()
    {
        return new CCProduct;
    }
};
 
//
 
// 主函數
int _tmain(int argc, _TCHAR* argv[])
{
    _tcout << _T("簡單工廠:") << endl;
    // 利用簡單工廠建立産品
    CSimpleFactory::CreateProduct(_T("A"))->Func();        // 建立産品A并調用
    CSimpleFactory::CreateProduct(_T("B"))->Func();        // 建立産品B并調用
    CSimpleFactory::CreateProduct(_T("C"))->Func();        // 建立産品C并調用
 
    _tcout << _T("工廠方法:") << endl;
    TSmartPtr<IFactory> c_p_factory;
    // 利用工廠方法建立産品
    c_p_factory = new CAFactory;
    c_p_factory->CreateProduct()->Func();            // 建立産品A并調用
    c_p_factory = new CBFactory;
    c_p_factory->CreateProduct()->Func();            // 建立産品B并調用
    c_p_factory = new CCFactory;
    c_p_factory->CreateProduct()->Func();            // 建立産品C并調用
 
    return 0;
}
 
//
/*
    Factory Method要解決的就是對象的建立時機問題.
    它通過面向對象的手法,将所要建立的具體對象的建立工作延遲到了子類,進而提供了一種擴充的政策,
    較好的解決了這種緊耦合的關系,很好地符合了開放封閉原則.
*/
//
           
  • Abstract_Factory.cpp
//
// 抽象工廠模式 C++示例
//
// Author:    木頭雲
// Blog:    http://darkc.at
// E-Mail:    [email protected]
// Version:    1.0.819.1540(2009/08/19)
//
 
#include "stdafx.h"
 
//
 
// 産品接口類
 
class IProduct abstract
{
public:
    virtual ~IProduct()
    {
    }
 
public:
    virtual void Func() = 0;
};
 
class IProduct2 abstract
{
public:
    virtual ~IProduct2()
    {
    }
 
public:
    virtual void Func2() = 0;
};
 
//
 
// 具體的産品類
 
class CAProduct : public IProduct
{
public:
    virtual void Func()
    {
        _tcout << _T("Product A") << endl;
    }
};
 
class CBProduct : public IProduct
{
public:
    virtual void Func()
    {
        _tcout << _T("Product B") << endl;
    }
};
 
class CCProduct : public IProduct
{
public:
    virtual void Func()
    {
        _tcout << _T("Product C") << endl;
    }
};
 
// 具體的産品類2
 
class CAProduct2 : public IProduct2
{
public:
    virtual void Func2()
    {
        _tcout << _T("Product2 A") << endl;
    }
};
 
class CBProduct2 : public IProduct2
{
public:
    virtual void Func2()
    {
        _tcout << _T("Product2 B") << endl;
    }
};
 
class CCProduct2 : public IProduct2
{
public:
    virtual void Func2()
    {
        _tcout << _T("Product2 C") << endl;
    }
};
 
//
 
// 簡單工廠類
class CSimpleFactory
{
public:
    static TSmartPtr<IProduct> CreateProduct(const _tstring& str)
    {
        if( str == _T("A") )
            return new CAProduct;
        else if( str == _T("B") )
            return new CBProduct;
        else if( str == _T("C") )
            return new CCProduct;
        else
            return NULL;
    }
 
    static TSmartPtr<IProduct2> CreateProduct2(const _tstring& str)
    {
        if( str == _T("A") )
            return new CAProduct2;
        else if( str == _T("B") )
            return new CBProduct2;
        else if( str == _T("C") )
            return new CCProduct2;
        else
            return NULL;
    }
};
 
//
 
// 抽象工廠接口類
class IAbstractFactory abstract
{
public:
    virtual TSmartPtr<IProduct> CreateProduct() = 0;
    virtual TSmartPtr<IProduct2> CreateProduct2() = 0;
};
 
// 抽象工廠類
 
class CAFactory : public IAbstractFactory
{
public:
    virtual TSmartPtr<IProduct> CreateProduct()
    {
        return new CAProduct;
    }
 
    virtual TSmartPtr<IProduct2> CreateProduct2()
    {
        return new CAProduct2;
    }
};
 
class CBFactory : public IAbstractFactory
{
public:
    virtual TSmartPtr<IProduct> CreateProduct()
    {
        return new CBProduct;
    }
 
    virtual TSmartPtr<IProduct2> CreateProduct2()
    {
        return new CBProduct2;
    }
};
 
class CCFactory : public IAbstractFactory
{
public:
    virtual TSmartPtr<IProduct> CreateProduct()
    {
        return new CCProduct;
    }
 
    virtual TSmartPtr<IProduct2> CreateProduct2()
    {
        return new CCProduct2;
    }
};
 
//
 
// 主函數
int _tmain(int argc, _TCHAR* argv[])
{
    _tcout << _T("簡單工廠:") << endl;
    // 利用簡單工廠建立産品
    CSimpleFactory::CreateProduct(_T("A"))->Func();        // 建立産品1A并調用
    CSimpleFactory::CreateProduct2(_T("A"))->Func2();    // 建立産品2A并調用
    CSimpleFactory::CreateProduct(_T("B"))->Func();        // 建立産品1B并調用
    CSimpleFactory::CreateProduct2(_T("B"))->Func2();    // 建立産品2B并調用
    CSimpleFactory::CreateProduct(_T("C"))->Func();        // 建立産品1C并調用
    CSimpleFactory::CreateProduct2(_T("C"))->Func2();    // 建立産品2C并調用
 
    _tcout << _T("抽象工廠:") << endl;
    TSmartPtr<IAbstractFactory> c_p_factory;
    // 利用抽象工廠建立産品
    c_p_factory = new CAFactory;
    c_p_factory->CreateProduct()->Func();                // 建立産品1A并調用
    c_p_factory->CreateProduct2()->Func2();                // 建立産品2A并調用
    c_p_factory = new CBFactory;
    c_p_factory->CreateProduct()->Func();                // 建立産品1B并調用
    c_p_factory->CreateProduct2()->Func2();                // 建立産品2B并調用
    c_p_factory = new CCFactory;
    c_p_factory->CreateProduct()->Func();                // 建立産品1C并調用
    c_p_factory->CreateProduct2()->Func2();                // 建立産品2C并調用
 
    return 0;
}
 
//
/*
    抽象工廠模式的重點思想在于面向接口程式設計.
    它提供了一個建立一系列相關或互相依賴對象的接口,運用抽象工廠模式的關鍵點在于應對"多系列對象建立"的需求變化.
*/
//
           

更多内容請通路:http://darkc.at