对象工厂 Object Factory
又名简单工厂模式,貌似不属于设计模式范畴。它的作用是把对象的创建工作集中起来,并使创建工作与其它部分解耦。比如下面这个函数也可当作简单工厂:
- CWinBase* Create(string s)
- {
- if(s == "Edit")
- return new CEdit;
- else if(s == "Button")
- return new CButton;
- ...
- }
Loki库的Factory类提供了对简单工厂模式的支持。
头文件
类型
- 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<int, 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)。
|