工廠模式:封裝物件的建立(二、多型工廠)
阿新 • • 發佈:2019-02-11
在上篇中,靜態成員函式 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)工廠方法模式