65.9K
CodeProject 正在变化。 阅读更多。
Home

C++ 中的工厂模式

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (58投票s)

2012年4月10日

CPOL

2分钟阅读

viewsIcon

360933

downloadIcon

3282

在 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 类的一些定义。特别是构造函数、RegisterCreateAnimal 函数。

构造函数

构造函数是你可以考虑注册你的 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;
}
© . All rights reserved.