工厂设计模式的实现与应用

在软件开发中,工厂设计模式是一种常用的创建型设计模式,它提供了一种创建对象的最佳方式。这种模式允许客户端通过接口请求对象,而无需指定将要创建的对象的确切类。本文将介绍如何实现一个简单的对象工厂,并展示如何通过模板元编程简化类的注册过程。

对象工厂的基本概念

对象工厂负责在运行时根据用户的操作或信息流动态创建对象。在编译时,要创建的对象类型是未知的,工厂只需要一个对象ID来创建对象,因为它在编译时已经注册了对象类。对象的创建利用了多态性,因此对象类应该从某个抽象类派生。

class CBase { public: CBase() {} virtual ~CBase() {} };

派生类必须从基类派生,并且在对象创建之前需要注册到工厂中。因此,派生类必须有两个静态函数:创建函数和注册函数,以及唯一的静态类型标识符。

class CDerived : public CBase { public: static const int m_id; CDerived() {} virtual ~CDerived() {} static CBase* CreateDerived() { return new CDerived; } static void RegisterDerivedClass(); };

其中CreateDerived是创建函数,类型标识符可以是任何对象,如整数、字符串等。为了简化,这里使用整数。

对象工厂类

对象工厂类维护一个类型标识符-创建函数对的容器,该容器是工厂类的一个成员。容器的初始化过程称为类(类型)注册。通常,工厂类被实现为单例模式。

class CFactory { public: typedef CBase* (*DerivedClassCreatorFn)(); private: CFactory() {} CFactory(const CFactory&); CFactory& operator=(const CFactory&); public: static CFactory& Instance() { static CFactory factory; return factory; } void RegisterClassCreator(int id, DerivedClassCreatorFn creatorFn) { m_mapClassCreators.insert(std::map::value_type(id, creatorFn)); } void UnregisterClassCreator(int id) { m_mapClassCreators.erase(id); } private: std::map m_mapClassCreators; };

在RegisterClassCreator和UnregisterClassCreator函数中省略了错误处理。

类型列表和模板元编程

为了简化类的注册过程,可以使用类型列表和模板元编程。Loki自由库提供了类型列表的定义和代码,但本文将直接提供所需的定义和宏定义。

template struct TypeList { typedef T Head; typedef U Tail; };

为了使代码更简洁,引入了宏定义。

#define TYPELIST_1(T1) TypeList #define TYPELIST_2(T1, T2) TypeList #define TYPELIST_3(T1, T2, T3) TypeList // ...

使用TypeList在MetaLoop中获取类类型。

如何工作

假设有四个类需要注册:CDerived0、CDerived1、CDerived2和CDerived3,以及它们各自的类型标识符。定义MetaLoop如下:

template struct RegDerivedClasses; template struct RegDerivedClasses, idx> { typedef Head Result; static inline void Fn() { Result::RegisterDerivedClass(); } }; template struct RegDerivedClasses, idx> { typedef typename RegDerivedClasses, idx-1>::Result Result; static inline void Fn() { Result::RegisterDerivedClass(); RegDerivedClasses, idx-1>::Fn(); } };

最后,定义别名:

typedef RegDerivedClasses RegClassStruct;

现在,要注册类,只需在应用程序中写入:

RegClassStruct::Fn();

建议将所有与类型列表和RegDerivedClasses结构相关的代码与基类、派生类和工厂类代码保持在同一文件中。

添加自己的类

假设想将自己的类CDerived4添加到工厂中。现在有五个类需要注册,四个旧类和一个新类。假设可以访问定义CDerived的源文件,按照以下步骤进行:

编写新类CDerived4,包括必需的成员CreateDerived和RegisterDerivedClass以及其唯一标识符。如果没有下一个TYPELIST的#define,编写一个新的:

#define TYPELIST_5(T1, T2, T3, T4, T5) TypeList typedef RegDerivedClasses RegClassStruct;

当然,可能还需要修改可执行代码以使用新添加的类,但这是另一回事。

演示应用程序

源代码在上面已经解释得很清楚了。本文附带的演示应用程序是用Microsoft VC++2010 Express编译的。(可以从Microsoft网站免费下载VC++ 2010 Express。)该应用程序注册了四个类CDerived0到CDerived3到工厂,并使用工厂创建类实例,并将类名写入控制台。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485