正文

编程如禅——工厂模式的智能化实现(c++)(2)(转帖)2007-04-05 00:13:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/oopfem/24607.html

分享到:

原文作者:曹骥   接上一帖,消除switch和case语句:   由名字创建对象其实的有挺强的背景,那就是软件工程学中的对象持久性问题。本文讨论的方法也是持久性的一个可能实现。废话少说,看看C++是怎么做的。   动态创建当然要用指针。我们不希望在程序中出现硬编码:   Shape * pShape = new Circle;   那就用函数/对象包装一下。函数包装简单、高效一些。于是有Circle类的成员函数:   Shape *createInstance() {return new Circle;}   我们需要用这个函数去创建Circle对象,同时只有Circle对象创建以后才可以调用createInstance()。这是一对矛盾。解决的办法是将createInstance()写成静态函数。于是Shpae和Circle类长的是这个样子:   class Shape{ public:        virtual void  Draw()  = 0; };   class Circle : public Shape{ public:        void Draw()  { std::cout << "Drawing a Circle......Done" << std::endl; }        static Shape *createInstance() {return new Circle;} };   指向createInstance()的函数指针当然要放在工厂类里面,同时要和创建对象的名字关联起来。std::map的键-值组合当然是最佳人选。我们还有如下定义:   typedef Shape *(*FactoryFunction)();   FactoryFunction就是一个指向函数的指针,而这个函数返回一个Shape *类型。如果你对FactoryFunction有疑问,可以看看关于函数指针的书。   有了FactoryFunction,我们来定义工厂类中的map:   std::map<std::string,FactoryFunction> m_FactoryFunctions;   这样的map对象是把名字(string类型)和函数指针作为一个组合。向工厂登记产品的时候,函数可以写成这样:   void ShapeFactory::Register(std::string name, FactoryFunction instanceFunction){ m_FactoryFunctions[name] = instanceFunction; }   登记Circle类的创建函数:   Register("circle", &Circle::createInstance);   ShapeFactory类中由名字得到函数指针可以写成这样:   Shape * ShapeFactory::getInstance(std::string name) { if (m_FactoryFunctions.count(name))  return m_FactoryFunctions[name]();        else  return NULL; }   map.count()的用法可以看看STL的手册。ShapeFacoty的完整定义如下:   class ShapeFactory { public:        static void Register(std::string name, FactoryFunction instanceFunction)               {m_FactoryFunctions[name] = instanceFunction;};        static Shape * getInstance (std::string name)               { if (m_FactoryFunctions.count(name))                     return m_FactoryFunctions[name]();                else       return NULL; } private:        static std::map<std::string,FactoryFunction> m_FactoryFunctions; };   std::map<std::string,FactoryFunction> ShapeFactory::m_FactoryFunctions;   其中Register()和getInstance()是静态函数,m_FactoryFunctions是静态成员变量。之所以这样做是避免创建ShapeFactory对象,以简化编程。同时便于用单例(Singleton)模式实现ShapeFactory。   这些完成以后,就可以向工厂登记产品和使用产品了。看看下面代码:   void someFunction() {        ShapeFactory::Register("circle", & Circle::createInstance);        Shape * pShape = NULL;        pShape = ShapeFactory::getInstance("circle");        if (NULL == pShape)        {               std::cout << "can't find the product in the factory" << std::endl;               delete pShape;        }        else        {               pShape->Draw();               delete pShape;        } }   怎么样,还不算复杂吧。有人会认为函数指针太不“面向对象”了,应该用其他方法。工厂模式的实现方法很多的,这里只是做一个例子。   注意观察上面的代码。这里已经没有了switch/case语句。而且ShapeFactory类和Shape类的定义和实现是完全封闭的。新添加的产品类将不改变工厂类和基类的代码。这是一个标志性的变化。当用户添加一个新产品的时候,他可以不管工厂已经有什么产品,也不用写丑陋的switch/case语句了。具体的产品是在运行时刻决定的。这样的工厂模式才具备实用价值,而不是简单的、对象/类之间的堆砌和关联。   当我们添加一个新产品的时候,比如Triangle,可以这样做:   1)      定义Triangle类: class Triangle : public Shape { public:     void Draw()  { std::cout << "Drawing a Triagnle......Done" << std::endl; }     static Shape *createInstance() {return new Triangle;} }; 2)      在合适的地方登记Triangle:        ShapeFactory::Register("triangle", & Triangle::createInstance); 3)      给出名字,就可以创建Triangle对象了: pShape = ShapeFactory::getInstance("triangle");   综上所述,我们的第一个目标已经实现:由名字创建对象。同时我们也详细讨论的工厂模式的实现。注意我们的工厂只是一个ConcreteFactory。在上面的新产品添加过程中,能不能省略第二步?能否实现产品在工厂中的自动登记?这将是我们要讨论的第二个问题。   目前的实现对JAVA和PYTHON程序员来说不是难事。但是产品自动登记可就不简单了。有谁可以在1周内做出来,我就转行学JAVA和PYTHON。   最后贴出完整代码(VC6和GCC都编译通过):   #pragma warning (disable:4786)   #include <iostream> #include <map> #include <string>   class Shape;   typedef Shape *(*FactoryFunction)();   class ShapeFactory { public:        static void Register(std::string name, FactoryFunction instanceFunction)               {m_FactoryFunctions[name] = instanceFunction;};        static Shape * getInstance(std::string name)               { if (m_FactoryFunctions.count(name))                     return m_FactoryFunctions[name]();                else       return NULL; } private:        static std::map<std::string,FactoryFunction> m_FactoryFunctions; };   std::map<std::string,FactoryFunction> ShapeFactory::m_FactoryFunctions;   class Shape { public:        virtual void  Draw()  = 0; };   class Circle : public Shape { public:        void Draw()  { std::cout << "Drawing a Circle......Done" << std::endl; }        static Shape *createInstance() {return new Circle;} };   class Triangle : public Shape { public:        void Draw()  { std::cout << "Drawing a Triagnle......Done" << std::endl; }        static Shape *createInstance() {return new Triangle;} };   int main() {        ShapeFactory::Register("circle",   &   Circle::createInstance);        ShapeFactory::Register("Triangle", & Triangle::createInstance);          Shape * pShape = NULL;          pShape = ShapeFactory::getInstance("circle");        if (NULL == pShape)        {               std::cout << "can't find the product in the factory" << std::endl;               delete pShape;        }        else        {               pShape->Draw();               delete pShape;        }        return 0; }

阅读(8492) | 评论(1)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册