1. 程式人生 > >工廠模式:封裝物件的建立(二、多型工廠)

工廠模式:封裝物件的建立(二、多型工廠)

在上篇中,靜態成員函式  static Shape* factory(const string& type) 迫使所有建立物件的操作都集中在一個地方,

因此這個地方就是唯一需要修改程式碼的地方。這是一個合理的決解方法,因為它完美的封裝了物件的建立過程。

但是工廠方法模式——可以使不同型別的的工廠派生自基本型別的工廠。工廠方法事實上就是多型工廠模式的一個特例。

所以下面例子是——工廠方法模式做為一個單獨的類中的虛函數出現。

#include <stdexcept>
#include <cstddef>
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>


using namespace std;


template<class Seq> void purge(Seq& c)  
{
    typename Seq::iterator i;
    for(i = c.begin(); i != c.end(); ++i) 
    {   
        delete *i; 
        *i = 0;
    }   
}


// Iterator version:
template<class InpIt> void purge(InpIt begin, InpIt end) 
{
    while(begin != end) 
    {   
        delete *begin;
        *begin = 0;
        ++begin;
    }   
}


class Shape
{
public:
    virtual void draw() = 0;
    virtual void erase() = 0;
    virtual ~Shape() {}
};




class ShapeFactory 
{
    virtual Shape* create() = 0;
    static map< string , ShapeFactory* > factories;
public:
    virtual ~ShapeFactory(){}
    friend class ShapeFactoryInitializer;
    class BadShapeCreation : public logic_error
    {   
    public:
        BadShapeCreation(string type): logic_error("Cannot create type " + type) {}
    };  


    static Shape * createShape(const string& id) throw(BadShapeCreation)
    {   
        if(factories.find(id) != factories.end())
            return factories[id]->create();
        else
            throw BadShapeCreation(id);
    }   


};
//define static object
map< string , ShapeFactory* > ShapeFactory::factories;




class Circle : public Shape 
{
    Circle() {} // Private constructor
    friend class ShapeFactoryInitializer;
    class Factory;
    friend class Factory;
    class Factory:public ShapeFactory
    {
        public:
            Shape* create()
            {
                return new Circle;
            }
            friend class ShapeFactoryInitializer;
    };
public:
    void draw()
    {
        cout << "Circle::draw" << endl;
    }
    void erase()
    {
        cout << "Circle::erase" << endl;
    }


    ~Circle()
    {
        cout << "Circle::~Circle" << endl;
    }
};
class Square : public Shape 
{
    Square() {}
    friend class ShapeFactoryInitializer;
    class Factory;
    friend class Factory;
    class Factory:public ShapeFactory
    {
        public:
            Shape* create()
            {
                return new Square;
            }
            friend class ShapeFactoryInitializer;
    };
public:
    void draw()
    {
        cout << "Square::draw" << endl;
    }
    void erase()
    {
        cout << "Square::erase" << endl;
    }
    ~Square()
    {
        cout << "Square::~Square" << endl;
    }
};


//Singleton to initialize the ShapeFactory
class ShapeFactoryInitializer
{
    static ShapeFactoryInitializer si;
    ShapeFactoryInitializer()
    {
        ShapeFactory::factories["Circle"]=new Circle::Factory;
        ShapeFactory::factories["Square"]=new Square::Factory;
    }
    ~ShapeFactoryInitializer()
    {
        map<string,ShapeFactory*>::iterator it=ShapeFactory::factories.begin();
        while(it!=ShapeFactory::factories.end())
            delete it++->second;
    }
};
//static member definition
ShapeFactoryInitializer ShapeFactoryInitializer::si;




char* sl[] = { "Circle", "Square", "Square","Circle", "Circle", "Circle", "Square"};




int main()
{


    vector<Shape*> shapes;
    try {
        for(size_t i = 0; i < sizeof sl / sizeof sl[0]; i++)
            shapes.push_back(ShapeFactory::createShape(sl[i]));
    } catch(ShapeFactory::BadShapeCreation e)
    {
        cout << e.what() << endl;


        return -1;
    }
    for(size_t i = 0; i < shapes.size(); i++)
    {
        shapes[i]->draw();
        shapes[i]->erase();
    }
    purge(shapes);
}
工廠方法模式作為virtual create() 出現在它自己的 ShapeFactory 類中,這是一個私有的成員函式。意味著不能直接呼叫它,但是可以被覆蓋。

Shape 的子類必須建立各自的 ShapeFactory子類,並且覆蓋成員函式 create()以建立其自身型別的物件。

這些工廠是私有的,只能被工廠方法模式訪問。採用這種方法的所有客戶程式碼都必須通過工廠方法模式建立物件。

Shape物件的實際建立是通過呼叫ShapeFactory::createShape() 完成對的,這是一個靜態成員函式,

使用ShapeFactory 中的map 根據傳遞給它的識別符號找到相應的工廠物件。

工廠直接建立Shape 物件,但是可以設想一個更為複雜的問題:在某個地方返回一個合適的工廠物件。然後該工廠物件被呼叫者用於以更復雜的方法建立一個物件。

然而,似乎在大多數情況下不需要這麼複雜地使用多型工廠方法模式。

注意,ShapeFactory 必須通過裝載它的map 與工廠物件進行初始化,這些操作發生在單例ShapeFactoryInitializer, 以便將工廠的一個例項插入到map中。

這些額外的複雜的操作再次暗示,如果不需要建立獨立的工廠物件,應該儘可能使用靜態(static)工廠方法模式