usidc5 | 2011-01-18 16:48 | 对象工厂 Object Factory又名简单工厂模式,貌似不属于设计模式范畴。它的作用是把对象的创建工作集中起来,并使创建工作与其它部分解耦。比如下面这个函数也可当作简单工厂:
CWinBase* Create(string s)
{
if(s == "Edit")
return new CEdit;
else if(s == "Button")
return new CButton;
...
}
Loki库的Factory类提供了对简单工厂模式的支持。
头文件#include
类型template<
class AbstractProduct, // “产品”基类型
typename IdentifierType, // 用什么区分各产品
typename CreatorParmTList = NullType, // 生成器参数
template< typename, class > class FactoryErrorPolicy = DefaultFactoryError>
class Loki::Factory;
成员方法
bool Register(const IdentifierType& id, ProductCreator creator); | 以id作为识别码注册生成器。函数、对象方法或仿函数都可以作为生成器。 | bool Unregister(const IdentifierType& id); | 取消注册 | std::vector RegisteredIds(); | 取得已注册的所有识别码 | AbstractProduct* CreateObject(const IdentifierType& id);
AbstractProduct* CreateObject(const IdentifierType& id, Parm1 p1);
AbstractProduct* CreateObject(const IdentifierType& id, Parm1 p1, Parm2 p2);
... | 按识别码id生成对象(调用对应的生成器) |
示例代码#include
#include
#include
#include
// 窗体基类
struct IWidget{
virtual void printName() = 0;
virtual ~IWidget(){;}
};
// 定义窗体工厂,使用string区分各对象类型
typedef Loki::Factory widget_factory_t;</iwidget, std::string>
// 按钮窗体
struct CButton : IWidget{
void printName()
{
std::cout << "CButton" << std::endl;
}
};
// 编辑框窗体
struct CEdit : IWidget{
void printName()
{
std::cout << "CEdit" << std::endl;
}
};
// 列表框窗体
struct CListBox : IWidget{
void printName()
{
std::cout << "CListBox" << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
// 工厂实例
widget_factory_t wf;
// 注册各种窗体的生成器,这里偷懒用了CreateUsingNew作为生成器
wf.Register("Edit", Loki::CreateUsingNew::Create );
wf.Register("Button", Loki::CreateUsingNew::Create );
wf.Register("ListBox", Loki::CreateUsingNew::Create );
// 测试,使用工厂生成窗体
{
IWidget* pWid = wf.CreateObject("Edit");
pWid->printName();
delete pWid;
}
{
IWidget* pWid = wf.CreateObject("ListBox");
pWid->printName();
delete pWid;
}
return 0;
}
很多时候,工厂往往只需要一个实例,我们可以使用前面说过的SingletonHolder把widget_factory_t弄成Singleton模式。
上面生成CButton之类的窗体时使用的是默认构造,所以我偷懒没写各个类的生成器,直接用了Loki::CreateUsingNew。
如果你的类有构造参数的话,那么就得在Loki::Factory模板参数中指出参数类型,并且自定义生成器,就象这样:
#include
#include
#include
// 窗体基类
struct IWidget{
virtual void printName() = 0;
virtual ~IWidget(){;}
};
// 定义窗体工厂,这里用Loki::Seq指定参数类型
typedef Loki::Factory<
IWidget,
std::string,
Loki::Seq<std::string, int</std::string, , char>
> widget_factory_t;
// 单件模式,注意Lifetime策略要选择Loki::LongevityLifetime::DieAsSmallObjectChild,否则...
typedef Loki::SingletonHolder<widget_factory_t, loki::createusingnew,< span=""></widget_factory_t, loki::createusingnew,<>
Loki::LongevityLifetime::DieAsSmallObjectChild> Singleton_Fac;
// 按钮窗体
struct CButton : IWidget{
void printName()
{
std::cout << "CButton:" << m_txt << std::endl;
}
CButton(std::string txt, int, char) //多个构造参数
:m_txt(txt){}
std::string m_txt;
};
// 编辑框窗体
struct CEdit : IWidget{
void printName()
{
std::cout << "CEdit:" << m_txt << std::endl;
}
CEdit(std::string txt, int, char) //多个构造参数
:m_txt(txt){}
std::string m_txt;
};
// 列表框窗体
struct CListBox : IWidget{
void printName()
{
std::cout << "CListBox:" << m_txt << std::endl;
}
CListBox(std::string txt, int, char) //多个构造参数
:m_txt(txt){}
std::string m_txt;
};
// 自定义的窗体构造器,用模板只是为了方便点^_^
template<class T> struct CreateT
{
T * operator()(std::string txt, int p1, char p2) const
{
return new T(txt, p1, p2);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
// 工厂实例
widget_factory_t& wf = Singleton_Fac::Instance();
// 注册各种窗体的生成器,用我们的生成器
wf.Register("Edit", CreateT() );
wf.Register("Button", CreateT() );
wf.Register("ListBox", CreateT() );
// 测试,使用工厂生成窗体
{
IWidget* pWid = wf.CreateObject("Edit", "Hello", 0, ' ');
pWid->printName();
delete pWid;
}
{
IWidget* pWid = wf.CreateObject("ListBox", "World", 0, ' ');
pWid->printName();
delete pWid;
}
return 0;
}
Loki::Seq是一个类似于TypeList的东东,可以存放一系列的类型。另外用SingletonHolder包装Factory时,一定要用Loki::LongevityLifetime::DieAsSmallObjectChild作为SingletonHolder的lifttime策略(Loki使用说明上说的,由于Factory使用了Loki内部的内存管理器SmallObject)。
|
|