如何在C++中实现支持动态添加动物类的自动键值工厂模式?
实现可扩展的动物领养工厂(无分支判断,支持运行时新增类型)
刚好我之前做过类似的动态工厂需求,完美匹配你的场景!咱们不用写一堆if/else或者switch来判断动物类型,而是用动态注册表+函数对象的方式,让Shelter能随时接收新的Animal子类,还能安全创建实例。
核心思路
咱们搞一个「动物类型注册表」,把动物的名称字符串(比如"parrot")和对应的实例创建函数绑定起来。Shelter只需要维护这个注册表,创建动物时直接根据名称查表调用创建函数就行。开发者要加新动物,只需要调用addAnimal把类型和创建逻辑注册进去,完全不用改原有代码。
第一步:定义基础类结构
首先得把Animal基类、物品类(如果要类型安全的话)还有各个动物子类先定义好。这里我优化了物品的传递方式,用std::vector<Item*>替代void*,避免裸指针的不安全问题;如果坚持要用void*,后面也可以调整。
1. 物品基类(可选,但更安全)
如果所有物品都有共性,可以抽象成基类:
class Item { public: virtual ~Item() = default; class Owner* owner; // 对应你说的Owner引用,供动物识别主人 }; // 具体物品类 class Collar : public Item {}; class Leash : public Item {}; class CatTree : public Item {}; class LitterBox : public Item {}; class Cage : public Item {};
2. Animal基类
class Animal { public: virtual ~Animal() = default; // 动物通用方法,比如makeSound() virtual void makeSound() = 0; };
3. 具体动物子类
每个子类的构造函数接收物品列表,并且可以加静态方法验证物品是否符合要求:
class Dog : public Animal { public: // 构造函数:接收物品列表 Dog(std::vector<Item*> items) : items_(std::move(items)) {} // 验证物品是否符合Dog的必需要求(项圈+牵引绳,无冗余) static bool validateItems(const std::vector<Item*>& items) { bool hasCollar = false, hasLeash = false; for (auto item : items) { if (dynamic_cast<Collar*>(item)) hasCollar = true; else if (dynamic_cast<Leash*>(item)) hasLeash = true; else return false; // 有冗余物品,直接返回false } return hasCollar && hasLeash; } void makeSound() override { std::cout << "Woof!" << std::endl; } private: std::vector<Item*> items_; }; class Cat : public Animal { public: Cat(std::vector<Item*> items) : items_(std::move(items)) {} static bool validateItems(const std::vector<Item*>& items) { bool hasTree = false, hasLitter = false; for (auto item : items) { if (dynamic_cast<CatTree*>(item)) hasTree = true; else if (dynamic_cast<LitterBox*>(item)) hasLitter = true; else return false; } return hasTree && hasLitter; } void makeSound() override { std::cout << "Meow!" << std::endl; } private: std::vector<Item*> items_; }; class Parrot : public Animal { public: Parrot(std::vector<Item*> items) : items_(std::move(items)) {} static bool validateItems(const std::vector<Item*>& items) { if (items.size() != 1 || !dynamic_cast<Cage*>(items[0])) { return false; } return true; } void makeSound() override { std::cout << "Polly wants a cracker!" << std::endl; } private: std::vector<Item*> items_; };
第二步:实现Shelter动态工厂
Shelter作为管理器,里面维护一个注册表,提供addAnimal注册新类型,getAnimal创建实例的方法:
#include <unordered_map> #include <functional> #include <stdexcept> #include <vector> class Shelter { public: // 单例模式(可选,方便全局访问) static Shelter& getInstance() { static Shelter instance; return instance; } // 注册新的动物类型:key是名称,creator是创建实例的函数 template<typename AnimalType> void addAnimal(const std::string& key) { // 把创建逻辑和验证逻辑封装成函数对象 registry_[key] = [](std::vector<Item*> items) -> Animal* { // 先验证物品是否符合要求 if (!AnimalType::validateItems(items)) { throw std::invalid_argument("Invalid items for " + key); } // 创建实例 return new AnimalType(std::move(items)); }; } // 根据名称创建动物实例 Animal* getAnimal(const std::string& key, std::vector<Item*> items) { auto it = registry_.find(key); if (it == registry_.end()) { throw std::invalid_argument("Unknown animal type: " + key); } // 调用注册的创建函数 return it->second(std::move(items)); } private: // 注册表:键=动物名称,值=创建函数 using CreatorFunc = std::function<Animal*(std::vector<Item*>)>; std::unordered_map<std::string, CreatorFunc> registry_; // 私有构造函数,禁止外部实例化(单例用) Shelter() = default; ~Shelter() = default; Shelter(const Shelter&) = delete; Shelter& operator=(const Shelter&) = delete; };
第三步:使用示例(Owner类调用)
现在Owner类可以直接调用Shelter的方法来领养动物,完全不用关心具体的类型判断:
class Owner { public: void adoptAnimal(const std::string& animalType) { // 准备对应动物的必需物品,注意设置owner引用 std::vector<Item*> items; if (animalType == "dog") { auto collar = new Collar(); collar->owner = this; auto leash = new Leash(); leash->owner = this; items = {collar, leash}; } else if (animalType == "cat") { auto tree = new CatTree(); tree->owner = this; auto litter = new LitterBox(); litter->owner = this; items = {tree, litter}; } else if (animalType == "parrot") { auto cage = new Cage(); cage->owner = this; items = {cage}; } try { Animal* pet = Shelter::getInstance().getAnimal(animalType, items); pet->makeSound(); // 后续可以把pet存到Owner的宠物列表里 } catch (const std::invalid_argument& e) { std::cerr << "Adoption failed: " << e.what() << std::endl; // 清理物品 for (auto item : items) delete item; } } }; // 主函数测试 int main() { // 先注册所有支持的动物类型 Shelter::getInstance().addAnimal<Dog>("dog"); Shelter::getInstance().addAnimal<Cat>("cat"); Shelter::getInstance().addAnimal<Parrot>("parrot"); // Owner领养动物 Owner me; me.adoptAnimal("parrot"); // 输出:Polly wants a cracker! me.adoptAnimal("dog"); // 输出:Woof! // 运行时新增动物类型(比如Hamster) class Hamster : public Animal { public: Hamster(std::vector<Item*> items) : items_(std::move(items)) {} static bool validateItems(const std::vector<Item*>& items) { // 假设Hamster需要小笼子 class HamsterCage : public Item {}; return items.size() == 1 && dynamic_cast<HamsterCage*>(items[0]); } void makeSound() override { std::cout << "Squeak!" << std::endl; } private: std::vector<Item*> items_; }; Shelter::getInstance().addAnimal<Hamster>("hamster"); // 准备Hamster的物品 Owner kid; auto hamsterCage = new Hamster::HamsterCage(); hamsterCage->owner = &kid; Animal* hamster = Shelter::getInstance().getAnimal("hamster", {hamsterCage}); hamster->makeSound(); // 输出:Squeak! // 记得清理内存(实际项目建议用智能指针) delete hamster; delete hamsterCage; return 0; }
关键细节说明
- 类型安全优化:我用
std::vector<Item*>替代了void*,避免了裸指针的类型不安全问题;如果你的项目必须用void*,可以把Shelter里的CreatorFunc改成std::function<Animal*(void*, int)>,然后在创建函数里把void*转换成对应的数组类型。 - 物品验证:每个动物子类的
validateItems静态方法确保物品是必需的且无冗余,不符合要求会抛出异常,避免创建出物品不全的动物。 - 运行时扩展:开发者只需要定义新的Animal子类,调用
addAnimal<NewAnimal>("new_animal")就能注册,完全不用修改Shelter的原有代码,符合开闭原则。 - 智能指针建议:实际项目里建议用
std::unique_ptr<Animal>替代裸指针,避免内存泄漏,比如把getAnimal的返回值改成std::unique_ptr<Animal>,创建函数里返回std::make_unique<AnimalType>(...)。
内容的提问来源于stack exchange,提问作者user1510024
相关产品推荐
相关产品推荐

