重温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最后一般会返回一个成品。

原文地址:https://www.cnblogs.com/strinkbug/p/1324876.html