• 重温gof版《设计模式》中的创建型模式


    这段时间一直忙于看sql server2005相关书籍,c++虽然每天都在用,很多知识没有复习,都渐渐荒废了。。。

    觉得作为一个c++程序员,基础性的东西一定要经常复习,比如语法性的东西、比如方向性的东西,如设计模式、比如方法性的东西,如重构,比如一些对我来说全新的东西,如模板

    1、关于factory method

    这两天抽空复习了gof版《设计模式》中的创建型模式,其实一直以来都对几个创建型模式比较混,感觉都差不多(singleton除外)。虽然常常在用,但是分不清。比如:

    代码一:
    //.h
    class CFactory
    {
            CFactory();
        
    public:
            ~CFactory();
        
    public:
            CProduct* CreateProduct(ProductType pt);
        
    public:
            
    static CFactory* m_pInstance;
            
    static CFactory* GetInstance();
            
    static void FreeInstance();
    };

    //.cpp
    CFactory* CFactory::m_pInstance = NULL;

    CFactory* CFactory::GetInstance()
    {
        
    if(m_pInstance == NULL)
            m_pInstance = 
    new CFactory();
        
    return m_pInstance;
    }

    CFactory* CFactory::FreeInstance()
    {
        delete m_pInstance;
        m_pInstance = NULL;
    }

    CProduct* CFactory::CreateProduct(ProductType pt)
    {
        
    switch(pt)
        {
        
    case ptCPU:
            
    return new CCPU();
        
    case ptMemory:
            
    return new CMemory();
        
    case ptHDD:
            
    return new CHDD();
        
    default:
            
    return NULL;

     }

    这是我经常使用的方式,这里既使用了singleton模式,又使用了factory method模式,可是这里究竟是否为factory method?我不确定,我觉得可能也可以叫做build 模式,谁知道呢,反正用着感觉不错。

    通过重新阅读gof的《设计模式》,我发觉这确实是一种factory method模式,更准确的说,这叫做:参数化工厂方法。

    Factory method更常用的方式是一对一,也就是一个产品对应一个factory method。这种一对一的factory method有个缺点,就是客户可能仅仅为了创建一个特定的contreteProduct对象,就不得不创建creator的子类。

    2、关于singleton模式

    关于Singleton模式,其实我一直有一个误用,还是以刚才那个CFactory为例。

    代码二:

    class CFactory

    {

             CFactory();

         public:

             ~CFactory();

         public:

             CProduct* CreateProduct(ProductType pt);

         public:

             static CFactory& GetInstance();

             {

                  static CFactory Instance;

                  return Instance;

             }

    };

    我已经忘了这种实现方式是从什么地方看来的,一般情况下这样的方式也确实能够工作,但是如果这个实现方式在一个dll中,然后该dll被多个客户端调用的情况下,单例往往就不是单例了,一般都会有多个。我已经被这种实现方式祸害很多次了。

    最好的方式还是使用代码一中的实现方式,不过代码一的实现方式有一点很讨厌,就是一定要在程序推出的时候调用FreeInstance,否则会有内存泄漏,而我们却常常会忘记。

     

    3、关于Prototype模式

    偶尔会有听说prototype模式,但是我一直以为这种模式不常用,觉得自己应该用不到,其实在日常开发的过程中,就常常在用。

    如果要用一句话概括:所有对Clone方法的实现对prototype模式的实现。

    Prototype就是一种拷贝,就是用一个已知的对象来创建一个新的对象,该模式在我的图形编辑器中就存在,在图形编辑器中复制黏贴对象的时候,使用的就是该模式。

    通过使用该模式,再结合Factory method模式,还有原型注册机制,我就可以用来实现我的图元库了。

     

    4、关于abstract factory

    迄今为止,我还没有使用过该模式,该模式也较为简单,就是在几类中定义出创建所有类型对象的接口,然后为每种系列的产品子类定一个工厂子类,如此而已。

    这种模式很不爽的一点就是:如果添加一种类型的产品,则要修改工厂基类和所有工厂子类的接口,修改量较大。

    一个可能的解决方案是:abstract factory中定义一个带参数的Make方法,参数可以是一个数字、一个字符串或者一个枚举,这些都无所谓。然后在工厂内部定义一个参数类型与产品类型的注册表,每次用户调用Make方法时,在Make方法中就通过参数来在注册表内查找指定类型的产品对象,然后调用该对象的Clone方法即可创建一个新的对象。

    那么问题又来了,工厂内的产品注册表从何而来呢?在下面的代码实现中,这个注册表由每个工厂子类来创建。

     

    代码三:

    class CProduct;

    //---------------------------------

    //.h

    //---------------------------------

    //抽象工厂

    class CAbstractFactory

    {

         CAbstractFactory(void);

    public:

         virtual ~CAbstractFactory(void);

     

    public: 

         //创建

    CProduct* Make(const std::string strName);

     

    protected:

         //名字与产品名称的键值对

         std::map< std::string, CProduct*> m_productDict;

     

    private:

         //工厂名称与具体工厂的键值对

         static std::map< std::string, CAbstractFactory*> m_factoryDict;

     

    public:

         static CAbstractFactory* GetInstance();

         static FreeInstance();

    };

     

    /////////////////////////////////////////////////////////

    class CFactory1:public CAbstractFactory

    {

         //在构造函数内做初始化

         CFactory1();

    public:

         virtual ~CFactory1();

         friend class CAbstractFactory;

    }

     

    /////////////////////////////////////////////////////////

    class CFactory2:public CAbstractFactory

    {

         //在构造函数内做初始化

         CFactory2();

    public:

         virtual ~CFactory2();

         friend class CAbstractFactory;

    }

     

    //---------------------------------

    //.cpp

    //---------------------------------

    #include "StdAfx.h"

    #include "AbstractFactory.h"

     

    std::map< std::string, CAbstractFactory*>  CAbstractFactory::m_factoryDict;

     

    CAbstractFactory::CAbstractFactory(void)

    {

    }

     

    CAbstractFactory::~CAbstractFactory(void)

    {

    }

     

     

    void CAbstractFactory::Register(const std::string strName, CProduct* pProduct)

    {

         m_productDict[strName] = pProduct;

    }

     

    CProduct* CAbstractFactory::Make(const std::string strName)

    {

         if(m_productName.find(strName) == m_productDict.end())

             return NULL;

         return m_productDict[strName]->Clone();

    }

     

    CAbstractFactory* CAbstractFactory::GetInstance()

    {

         //从环境变量中得到当前的工厂类型

         //也可以从某一全局变量中获取

         std::string strenv = getevn("factoryType");

         if(m_factoryDict.find(strevn) == m_factoryDict.end())

         {

             if(strenv == "factory1")

                  m_factoryDict[strenv] = new CFactory1();

             else if(strenv == "factory2")

                  m_factoryDict[strenv] = new CFactory2();

             else if(strenv == "factory3")

                  m_factoryDict[strenv] = new CFactory3();

             else return NULL;

         }

         return m_factoryDict[strenv];

    }

     

     

    ///////////////////////////////////////////////////////

    CFactory1::CFactory1()

    {

         m_productDict["CPU"] = new CCPU1();

         m_productDict["Memory"] = new CMemory1();

         m_productDict["HDD"] = new CCHDD1();

    }

     

     

    CFactory2::CFactory2()

    {

         m_productDict["CPU"] = new CCPU2();

         m_productDict["Memory"] = new CMemory2();

         m_productDict["HDD"] = new CCHDD2();

    }

     

    其实在该实现中,具体工厂可以不使用产品注册表,产品类也不需要实现Clone方法,只需将Make方法申明为virtual,然后在每个工厂子类中override该方法,在该方法内使用if else来判断并创建具体的产品即可。如:

     

    代码四:

    CProduct* CFactory2::Make(const std::string strName)

    {

         if(strName == "CPU")

             return new CCPU2;

         else if(strName == "Memory")

             return new CMemory2();

         else if(strName == "HDD")

             return new CHDD2();

         else

             return NULL;

    }

     

    5、关于builder

    一直以来,我就将builderfactory method混淆。今天阅读之后发现原来builderabstract factory是类似的,但是builder更偏向于创建部件,builder最后一般会返回一个成品。

  • 相关阅读:
    morning
    周末,又见周末
    One Care, still Care
    Linux 下挂载硬盘的 方法
    Oracle 11g Alert log 文件位置的问题
    Oracle中 drop user 和 drop user cascade 的区别
    如何加快建 index 索引 的时间
    Oracle ADDM 自动诊断监视工具 介绍
    Vmware SERVER 简介
    Oracle Logminer 说明
  • 原文地址:https://www.cnblogs.com/strinkbug/p/1324876.html
Copyright © 2020-2023  润新知