使用空基类强制继承实现抽象工厂是否为不良实践?
关于空基类实现抽象工厂的看法与改进方案
你提到的这种用empty_base_factory强制统一类型的做法确实比较生硬,本质上是在绕开C++静态类型系统的限制——因为factoryA::make_object和factoryB::make_object返回不同的智能指针类型(shared_ptr<A> vs shared_ptr<B>),没法直接定义一个包含纯虚make_object方法的基类接口。这种方式的弊端很明显:
- 空基类没有任何约束能力,完全依赖开发者手动保证所有派生工厂都实现了
make_object,很容易出错; - 代码可读性差,其他维护者看到
empty_base_factory会困惑它的实际作用; - 从
abstract_factory获取工厂后,还需要手动向下转型才能调用make_object,既繁琐又不安全。
下面给你几个更合理的改进方向:
1. 按产品类型拆分抽象工厂(最符合经典设计模式)
经典抽象工厂模式的核心是创建一组相关或相互依赖的对象,如果你的A和B是不相关的产品系列,完全可以把它们的工厂分开管理:
// 针对A系列的抽象工厂 struct AbstractFactoryA { virtual ~AbstractFactoryA() = default; virtual std::shared_ptr<A> make_object() = 0; }; struct FactoryA : public AbstractFactoryA { std::shared_ptr<A> make_object() override { return std::make_shared<DerivedA>(); // DerivedA是A的派生类 } }; // 针对B系列的抽象工厂 struct AbstractFactoryB { virtual ~AbstractFactoryB() = default; virtual std::shared_ptr<B> make_object() = 0; }; struct FactoryB : public AbstractFactoryB { std::shared_ptr<B> make_object() override { return std::make_shared<DerivedB>(); // DerivedB是B的派生类 } }; // 可以用一个总工厂来管理这两个抽象工厂(如果需要的话) class GlobalFactory { private: std::shared_ptr<AbstractFactoryA> factory_a; std::shared_ptr<AbstractFactoryB> factory_b; public: GlobalFactory() : factory_a(std::make_shared<FactoryA>()), factory_b(std::make_shared<FactoryB>()) {} std::shared_ptr<AbstractFactoryA> get_factory_a() { return factory_a; } std::shared_ptr<AbstractFactoryB> get_factory_b() { return factory_b; } };
这种方式完全利用了C++的多态特性,接口清晰,类型安全,也符合单一职责原则。
2. 用类型擦除统一工厂接口(适合必须统一管理的场景)
如果一定要把所有工厂放在同一个容器里,可以用类型擦除技术,通过std::any或std::variant统一返回类型:
struct BaseFactory { virtual ~BaseFactory() = default; virtual std::any make_object() = 0; }; struct FactoryA : public BaseFactory { std::any make_object() override { return std::make_shared<DerivedA>(); } }; struct FactoryB : public BaseFactory { std::any make_object() override { return std::make_shared<DerivedB>(); } }; class AbstractFactory { private: std::map<uint8_t, std::shared_ptr<BaseFactory>> iv_factories; public: AbstractFactory() { iv_factories[0] = std::make_shared<FactoryA>(); iv_factories[1] = std::make_shared<FactoryB>(); } template<typename Product> std::shared_ptr<Product> create_object(uint8_t key) { auto it = iv_factories.find(key); if (it == iv_factories.end()) { throw std::invalid_argument("Invalid factory key"); } // 类型转换,需要确保key对应的工厂确实返回Product类型 return std::any_cast<std::shared_ptr<Product>>(it->second->make_object()); } };
使用时直接调用create_object指定目标类型即可:
AbstractFactory af; auto a = af.create_object<A>(0); auto b = af.create_object<B>(1);
这种方式的代价是运行时类型转换的开销,以及需要开发者保证key和产品类型的对应关系,但至少比空基类的方式更清晰。
3. 用模板简化工厂注册(最简洁的实现)
如果不想手动编写每个工厂类,可以用模板函数直接注册产品的创建逻辑,完全省去中间工厂类:
class AbstractFactory { private: using CreateFunc = std::function<std::any()>; std::map<uint8_t, CreateFunc> creators; public: // 注册产品类型和对应的key template<typename Product> void register_product(uint8_t key) { creators[key] = []() { return std::make_shared<Product>(); }; } // 根据key创建指定类型的产品 template<typename Product> std::shared_ptr<Product> create_object(uint8_t key) { auto it = creators.find(key); if (it == creators.end()) { throw std::invalid_argument("Invalid product key"); } return std::any_cast<std::shared_ptr<Product>>(it->second()); } };
使用时只需要注册派生类:
AbstractFactory af; af.register_product<DerivedA>(0); af.register_product<DerivedB>(1); auto a = af.create_object<A>(0); auto b = af.create_object<B>(1);
这种方式代码量最少,灵活性也最高,不需要额外的工厂类或空基类,非常适合快速实现工厂模式。
内容的提问来源于stack exchange,提问作者Andre Marin
相关产品推荐
相关产品推荐

