这段时间一直忙于看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
一直以来,我就将builder和factory method混淆。今天阅读之后发现原来builder和abstract factory是类似的,但是builder更偏向于创建部件,builder最后一般会返回一个成品。