C++ 中的工厂模式






4.88/5 (58投票s)
在 C++ 中使用工厂模式来仅暴露对象的抽象类型,隐藏实现类的细节。
概述
到目前为止,我并没有经常在 C++ 中使用工厂模式。最近,我在一个项目中使用到了它,并且发现它对我的目的很有用,所以我认为我可以分享一个关于如何在 C++ 中使用工厂模式的教程。
Factory
模式完全一致,但据我理解,Factory
模式,它已经非常接近甚至完全一致了。定义
基本上,一个工厂由一个接口类组成,该接口类对于工厂将创建的所有实现类都是通用的。然后你拥有工厂类,通常是一个单例类,它生成这些实现类的实例。
抽象接口类
所以让我们先创建一个快速的接口类。在这个例子中,我使用了 IAnimal
:
class IAnimal
{
public:
virtual int GetNumberOfLegs() const = 0;
virtual void Speak() = 0;
virtual void Free() = 0;
};
为了简单起见,我使用了一个 typedef
来定义实现类用来创建 IAnimal
实例的函数类型。这个 typedef
也用于声明将动物名称映射到创建该特定类型动物的函数的映射。你可以使用任何调用约定,但在这个例子中,我选择了 __stdcall
。
typedef IAnimal* (__stdcall *CreateAnimalFn)(void);
具体的实现类
现在是实现类。这些类实现了 IAnimal
接口。这里有一些例子
// IAnimal implementations
class Cat : public IAnimal
{
public:
int GetNumberOfLegs() const { return 4; }
void Speak() { cout << “Meow” << endl; }
void Free() { delete this; }
static IAnimal * __stdcall Create() { return new Cat(); }
};
class Dog : public IAnimal
{
public:
int GetNumberOfLegs() const { return 4; }
void Speak() { cout << “Woof” << endl; }
void Free() { delete this; }
static IAnimal * __stdcall Create() { return new Dog(); }
};
class Spider : public IAnimal // Yeah it isn’t really an animal…
{
public:
int GetNumberOfLegs() const { return 8; }
void Speak() { cout << endl; }
void Free() { delete this; }
static IAnimal * __stdcall Create() { return new Spider(); }
};
class Horse : public IAnimal
{
public:
int GetNumberOfLegs() const { return 4; }
void Speak() { cout << “A horse is a horse, of course, of course.” << endl; }
void Free() { delete this; }
static IAnimal * __stdcall Create() { return new Horse(); }
};
工厂类声明
现在是 Factory
类。这是一个单例模式的实现——意味着工厂的实例只能被实例化一次,不多也不少。
// Factory for creating instances of IAnimal
class AnimalFactory
{
private:
AnimalFactory();
AnimalFactory(const AnimalFactory &) { }
AnimalFactory &operator=(const AnimalFactory &) { return *this; }
typedef map FactoryMap;
FactoryMap m_FactoryMap;
public:
~AnimalFactory() { m_FactoryMap.clear(); }
static AnimalFactory *Get()
{
static AnimalFactory instance;
return &instance;
}
void Register(const string &animalName, CreateAnimalFn pfnCreate);
IAnimal *CreateAnimal(const string &animalName);
};
工厂类实现
现在我们需要解决 AnimalFactory
类的一些定义。特别是构造函数、Register
和 CreateAnimal
函数。
构造函数
构造函数是你可以考虑注册你的 Factory
函数的地方。虽然这不必在这里完成,但我在这里完成了它,以用于这个例子。例如,你可以从代码中的其他地方将你的 Factory
类型与 Factory
类一起注册。
/* Animal factory constructor.
Register the types of animals here.
*/
AnimalFactory::AnimalFactory()
{
Register(“Horse”, &Horse::Create);
Register(“Cat”, &Cat::Create);
Register(“Dog”, &Dog::Create);
Register(“Spider”, &Spider::Create);
}
类型注册
现在让我们实现 Register
函数。由于我使用了一个 std::map
来保存我的 string
(动物类型)和 create
函数之间的映射,因此这个函数非常简单。
void AnimalFactory::Register(const string &animalName, CreateAnimalFn pfnCreate)
{
m_FactoryMap[animalName] = pfnCreate;
}
类型创建
最后但并非最不重要的是,CreateAnimal
函数。这个函数接受一个 string
参数,该参数对应于在 AnimalFactory
构造函数中注册的 string
。当此函数接收到“Horse
”时,它将返回一个 Horse
类的实例,该类实现了 IAnimal
接口。
IAnimal *AnimalFactory::CreateAnimal(const string &animalName)
{
FactoryMap::iterator it = m_FactoryMap.find(animalName);
if( it != m_FactoryMap.end() )
return it->second();
return NULL;
}
示例用法程序
int main( int argc, char **argv )
{
IAnimal *pAnimal = NULL;
string animalName;
while( pAnimal == NULL )
{
cout << “Type the name of an animal or ‘q’ to quit: “;
cin >> animalName;
if( animalName == “q” )
break;
IAnimal *pAnimal = AnimalFactory::Get()->CreateAnimal(animalName);
if( pAnimal )
{
cout << “Your animal has ” << pAnimal->GetNumberOfLegs() << ” legs.” << endl;
cout << “Your animal says: “;
pAnimal->Speak();
}
else
{
cout << “That animal doesn’t exist in the farm! Choose another!” << endl;
}
if( pAnimal )
pAnimal->Free();
pAnimal = NULL;
animalName.clear();
}
return 0;
}