C++实现工厂设计模式

本文介绍了如何使用C++实现工厂设计模式来实现数据驱动的对象创建。通过定义Object基类和Creator基类,以及使用宏辅助定义,实现了根据配置文件中的类型ID动态创建不同类型的对象,避免了switch语句的硬编码,符合开闭原则。此外,还设计了一个单例的ObjectFactory类用于管理对象的创建,并提供了注册方法,使得新类型对象的添加更加灵活。测试部分展示了如何注册和创建不同类型的对象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++实现工厂设计模式

  • 在做Data-Driven设计的时候,我们希望能对象的创建能依运行时文件的读入而不是硬编码在代码里。比如在设计游戏时,我们希望能够做到根据外部配置文件(可由游戏设计器生成)自动生成对象,并且配置好对象的属性。
  • 这时,我们需要做到的时根据文件的信息判断处需要创建出哪种类型的对象,这时我们可能想到的方法是
// 从配置文件中解析出typeID
switch (typeID) {
case PLAYER : return Player();
case TANK : return Tank();
case TREE : return Tree();
...
default : return nullptr;
}
  • 这样是可行的,但是当我们需要增加新的可能被以这种形式创建的类型的对象时,我们则需要在switch语句中添加新的一行,并且在定义TypeID类型的地方添加新的类型的ID,这显然时不符合开闭原则的。这时,我们可以借助工厂模式实现Data-Driven的创建对象。
  • 工厂模式的核心就是工厂类,工厂类提供一个函数,可以根据传入参数代表的欲创建的对象的的类型(TypeID)来创建出对象,总之就是,你喂给它类型,他吐出来这种类型的对象。

定义Object基类:

  • 工厂的一个函数可以返回不同类型的对象,所以我们考虑让这些需要被工厂创建的类型都继承于Object类,工厂创建就返回Object的指针类型。并且每个继承于Object的类型都必须手写一个获取类型ID的函数,以实现ID和类型相联系。
class Object {
public:
    virtual ~Object() = default;
};

// 定义ID函数辅助宏

#define DEFILE__GET_TYPE_ID(type) \
    static const std::string & getTypeID() { \
        static const std::string ID = #type; \
        return ID; \
    }

定义Creator基类:

  • 我们需要根据传入的类型ID动态的选择创建哪种类型的对象,Java中的反射可以实现这一点,但是C++没有原生支持的反射,这里我们通过借助Creator实现创建对象,不同的Creator能创建不同类型的对象。
  • 届时,我们通过ID检索到Creator然后再通过Creator的创建函数实现对象的创建。为了能将Creator组织起来,我们将定义Creator基类,每个不同类型对应的Creator都将继承于此。
class Creator {
public:
    Creator() = default;
    virtual Object * create() = 0;
    virtual ~Creator() = default;
};

// 定义Creator 辅助宏
#define DEFILE__CREATOR(type) \
    class type##Creator : public Creator { \
        public: \
            type##Creator() = default; \
            virtual Object * create() override { \
                return new type(); \
            } \
            virtual ~type##Creator() = default; \
    };

定义工厂类的初步结构:

  • 我们想要通过ID检索到Creator然后再通过Creator的创建函数实现对象的创建,就要将Creator和ID建立关系并组织起来,这里我们采用std::map。
  • 我们的工厂不需要多个,全局只需一个即可,应该设计成单例。
  • 并且,我们应该为工厂添加注册方法,实现利用ID和对应的Creator为这种类型的对象注册信息,实现工厂式创建。
class ObjectFactory {
public:
    Object * create(const std::string & typeID) {
        auto iter = creators.find(typeID);
        
        if (iter != creators.end()) return iter->second->create();
        
        return nullptr;
    }
    
    void registe(const std::string & id, Creator * c) {
        auto iter = creators.find(id);
        
        if (iter == creators.end()) creators[id] = c;
    }
    
    ~ObjectFactory() {
        for (auto p : creators) {
            if (p.second) delete p.second;
        }
    }
    
public:
    static ObjectFactory * getInstance() {
        static ObjectFactory instance;
        
        return &instance;
    }
private:
    ObjectFactory() = default;
    std::map<std::string, Creator*> creators;
};
// 定义注册辅助宏
#define REGISTE(type) \
    ObjectFactory::getInstance()->registe( \
        type::getTypeID(), new type##Creator());

测试:

class A : public Object {
public:
    A() {
        std::cout << "A\n";
    }
    DEFILE__GET_TYPE_ID(A)
};
DEFILE__CREATOR(A)


class B : public Object {
public:
    B() {
        std::cout << "B\n";
    }
    DEFILE__GET_TYPE_ID(B)
};
DEFILE__CREATOR(B)


class Player : public Object {
public:
    Player() {
        std::cout << "Player\n";
    }
    DEFILE__GET_TYPE_ID(Player)
};
DEFILE__CREATOR(Player)


int main() {
    REGISTE(A);
    REGISTE(B);
    REGISTE(Player);
    
    // in main-function
    ObjectFactory::getInstance()->create("A");
    ObjectFactory::getInstance()->create("B");
    ObjectFactory::getInstance()->create("B");
    ObjectFactory::getInstance()->create("Player");
    ObjectFactory::getInstance()->create("Player");
    return 0;
}

测试结果:

测试结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值