zoukankan      html  css  js  c++  java
  • 工厂对象模式简介

    工厂对象模式简介

    在GoF的《设计模式》一书中,对Factory Method/Object Method 意图描述如下:

    定义一个用于创建对象的接口,让子类决定实例化是哪一个类。 Factory Metho是一个类的实例化延迟到其子类。

    其结构图如下:

    ObjectFactory

    其中, 类 Product 定义了一类对象的接口。 ConcreteProduct 实现 Product 的接口。 Creator是工厂方法的包装器。ConcreteCreator 类实现Creator的接口。基于以上结构,每个ConcreteProduct必须带有一个 ConcreteCreator, 用来产生特定的ConcreteProduct。

    这种实现的缺点,在《设计模式》一书中也提到过一点 是客户可能仅仅想创建一个特定的 ConcreteProduct 对象,但必须额外创建 Creator 的子类。 在ConcreteProduct 的演化上造成额外的工作量。 另一点从代码简洁之道角度来看,每一个 ConcreteCreator 的实现都几乎一样,就像一幕幕乏味的样板戏,简直就是鸡肋。

    那么如何改进呢?

     

    用boost factory & boost function实现对象工厂

    文件:ObjectFactory.h

      

    1. #ifndef MP_OBJECT_FACTORY_H  
    2. #define MP_OBJECT_FACTORY_H  
    3. #include <boost/function.hpp>  
    4. #include <map>  
    5.   
    6. /// 工厂模式泛型实现.  
    7. /// 限制: 生成的对象必须为通过默认构造函数来构造.  
    8. /// 当然你也可以扩展这个模板让它支持更多参数的构造函数.  
    9. template<typename IdType, typename ObjectType>  
    10. class ObjectFactory  
    11. {  
    12. public:  
    13.     /// 表示默认构造函数的函数对象.  
    14.     typedef boost::function< ObjectType* () > CreatorType;  
    15.   
    16.     /// 构造函数对应的函数对象的关联容器.   
    17.     typedef std::map<IdType, CreatorType> ObjectCreator_map;  
    18.   
    19.     /// 注册子类对象的构造函数信息.  
    20.     void RegisterObjectCreator(const IdType& id, const CreatorType &creator)  
    21.     {  
    22.         objectCreatorMap_[id] = creator;  
    23.     }  
    24.   
    25.     /// 通过默认构造函数在堆上创建一个新的对象实例. 使用new生成.  
    26.     ObjectType * MakeObject(const IdType& id)  
    27.     {  
    28.         ObjectCreator_map::const_iterator iter = objectCreatorMap_.find(id);  
    29.         if (iter == objectCreatorMap_.end())  
    30.         {  
    31.             return NULL;  
    32.         }  
    33.         else  
    34.         {  
    35.             return (iter->second)();  
    36.         }  
    37.     }  
    38.   
    39. private:  
    40.     ObjectCreator_map objectCreatorMap_;  
    41. };  
    42.   
    43. #endif  

    以上代码中,模板ObjectFactor接收两个参数,第一个参数IdType是用来标识是哪种子类对象的关键字。ObjectType是基类对 象类型。也就是上面结构图中的Product。为了实现创建ConcreteProduct对象的方法,我们需要获得每个子类对象的构造函数信息,通过 RegisterObjectCreator方法我们将子类对象的构造函数信息保存在工厂中。  那么哪种数据结构表示构造函数信息呢? 通过普通函数指针,好像行不通。在这里我们用到了 boost::function,它可以将任意的函数信息封装到function object对象中,从而可以实现赋值,调用等操作。

    以上工厂实现中我们将任意类型的默认构造函数信息用 boost::function 进行封装,表示成 typedef boost::function< ObjectType* () > CreatorType;

    后面我们就是建一张表来关联IdType与它所对应ConcreteProduct的构造函数信息。这里我们直接用 std::map关联容器来存储。

    RegisterObjectCreator用于注册ConcreteProduct对象的构造函数信息。

    MakeObject用于根据传入的IdType来生成对应的ConcreteProduct对象。注意这一句 (iter->second)(); 它返回指向ObjectType对象的指针。  实际上iter->second返回是一个CreatorType 类型函数对象,对一个函数对象进行()调用。因为CreatorType是对构造函数的封装,因此实际上是调用ConcreteProduct的构造函数 生成一个ConcreteProduct对象。 后面会看到 CreatorType 是我们用 boost::factory 封装的,它默认会调用new操作符从堆上构造一个ConcreteProduct对象。

    如何使用对象工厂

    我们来实现GoF Factory Method结构图中类似的代码。

    首先我们定义几个类:

    Product                  --  产品类接口封装,定义了类对象的接口。

    ConcreteProductA  --  具体的产品A,该类 实现 Product 的接口。

    ConcreteProductB  --  具体的产品B,该类 实现 Product 的接口。

    文件:Product.h

    1. #ifndef MP_PRODUCT_H  
    2. #define MP_PRODUCT_H  
    3. #include <boost/shared_ptr.hpp>  
    4.   
    5. class Product  
    6. {  
    7. public:  
    8.     explicit Product() {};  
    9.     virtual ~Product() {};  
    10.     virtual void DoSomething() = 0;  
    11. };  
    12.   
    13. typedef boost::shared_ptr<Product> Product_ptr;  
    14.   
    15. #endif  

    文件:ConcreteProductA.h

    1. #ifndef MP_CONCRETE_PRODUCT_A_H  
    2. #define MP_CONCRETE_PRODUCT_A_H  
    3. #include <iostream>  
    4.   
    5. class ConcreteProductA  
    6.     :public Product  
    7. {  
    8. public:  
    9.     void DoSomething()  
    10.     {  
    11.         std::cout<<__FUNCTION__<<std::endl;  
    12.     }  
    13. };  
    14.   
    15.   
    16. #endif  

    文件:ConcreteProductB.h

    1. #ifndef MP_CONCRETE_PRODUCT_B_H  
    2. #define MP_CONCRETE_PRODUCT_B_H  
    3. #include <iostream>  
    4.   
    5. class ConcreteProductB  
    6.     :public Product  
    7. {  
    8. public:  
    9.     void DoSomething()  
    10.     {  
    11.         std::cout<<__FUNCTION__<<std::endl;  
    12.     }  
    13. };  
    14.   
    15.   
    16. #endif  

    下面我们来测试上面的对象工厂。

    文件: Main.cpp

    1. #include "Product.h"  
    2. #include "ConcreteProductA.h"  
    3. #include "ConcreteProductB.h"  
    4. #include "ObjectFactory.h"  
    5. #include <string>  
    6. #include <boost/functional/factory.hpp>  
    7.   
    8.   
    9. int main(int argc, char **argv)  
    10. {  
    11.     ObjectFactory<std::string, Product> productFactory; // 对象工厂  
    12.      
    13.     // 注册对象构造器.  
    14.     productFactory.RegisterObjectCreator("PRODUCT_A", boost::factory<ConcreteProductA *>() );  
    15.     productFactory.RegisterObjectCreator("PRODUCT_B", boost::factory<ConcreteProductB *>() );  
    16.   
    17.     //通过工厂生成对象, 存储在shared_ptr中.  
    18.     Product_ptr productA( productFactory.MakeObject("PRODUCT_A") );  
    19.     Product_ptr productB( productFactory.MakeObject("PRODUCT_B") );  
    20.   
    21.     // 演示多态性质。  
    22.     productA->DoSomething();  
    23.     productB->DoSomething();  
    24.     return 0;  
    25. }  

      

    在以上测试中,我们首先生成一个对象工厂,这里我们以std::string作为IdType来标示是哪种类型的ConcreteProduct。

    然后向工厂中注册具体类的构造方法: productFactory.RegisterObjectCreator("PRODUCT_A", boost::factory<ConcreteProductA *>() ); 注意:这里用到了boost::factory,它可以将 new 表达式封装成函数对象(function object),  这也正式我们工厂的注册方法所需要的参数。

    后面我们调用对象工厂的MakeObject来生成我们期望的ConcreteProduct对象。 我们用一个字符串来标识要生成哪种类型的ConcreteProduct对象。同时我们将返回的对象指针保存在 shared_ptr中,从而实现对象的自动管理。 类型Product_ptr的定义为: typedef boost::shared_ptr<Product> Product_ptr;  它是对Product接口的智能指针封装。

    最后,就是展示多态行为的时候了,我们调用不同ConcreteProduct对象的DoSomething来演示。运行效果如下:

     捕获

    限制说明:

    1. 本文只是实现了带有默认构造函数的对象工厂。 如果你愿意也可以实现带有多个参数构造函数的对象工厂。

    2. ObjectFactory 也可以实现为Singleton模式,根据个人需要吧,本文的重点不在这里。

    参考资料:

    1.  《设计模式可复用面向对象软件的基础》/ Design Patterns:Elements of Reusable Object-Oriented software  GoF

    2. 《C++_设计新思维》 / Modern C++ Design    Andrei Alexandrescu

    3.  Boost.Functional/Factory document             Tobias Schwinger

    4. Boost.Function document                              Douglas Gregor

  • 相关阅读:
    hdu 5101 Select
    hdu 5100 Chessboard
    cf B. I.O.U.
    cf C. Inna and Dima
    cf B. Inna and Nine
    cf C. Counting Kangaroos is Fun
    Radar Installation 贪心
    spfa模板
    Sequence
    棋盘问题
  • 原文地址:https://www.cnblogs.com/zhoug2020/p/5912281.html
Copyright © 2011-2022 走看看