1. 工厂模式基础回顾
工厂模式是面向对象设计中最为经典的模式之一,它通过将对象创建的逻辑封装在单独的类或方法中,实现了创建逻辑与使用逻辑的解耦。在C++这种没有内置反射机制的语言中,工厂模式尤为重要。
传统工厂模式通常分为三种基本形式:
- 简单工厂(Simple Factory):通过一个静态方法根据输入参数返回不同派生类对象
- 工厂方法(Factory Method):定义一个创建对象的接口,但让子类决定实例化哪个类
- 抽象工厂(Abstract Factory):提供一个创建一系列相关或依赖对象的接口,而无需指定它们的具体类
注意:简单工厂严格来说并不是GoF 23种设计模式之一,但在实际工程中应用非常广泛
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 工厂模式的常见变体
2.1 模板工厂(Template Factory)
模板工厂结合了模板元编程技术,可以在编译期确定具体产品类型。这种变体特别适合类型已知且需要极致性能的场景。
cpp复制template <typename ProductType>
class TemplateFactory {
public:
static ProductType* Create() {
return new ProductType();
}
};
// 使用示例
auto product = TemplateFactory<ConcreteProduct>::Create();
优势:
- 完全编译期确定类型,零运行时开销
- 类型安全,避免dynamic_cast等运行时检查
- 可结合CRTP模式实现更复杂的编译期多态
2.2 自注册工厂(Self-registering Factory)
自注册工厂允许产品类自动向工厂注册,无需显式修改工厂代码。这种变体在插件系统开发中特别有用。
实现要点:
- 使用静态变量在全局初始化阶段完成注册
- 维护产品类型名称到创建函数的映射表
- 通常需要借助宏简化注册代码
cpp复制class Factory {
using Creator = std::function<BaseProduct*()>;
static std::map<std::string, Creator>& Registry() {
static std::map<std::string, Creator> registry;
return registry;
}
public:
static void Register(const std::string& name, Creator creator) {
Registry()[name] = creator;
}
static BaseProduct* Create(const std::string& name) {
auto it = Registry().find(name);
return it != Registry().end() ? it->second() : nullptr;
}
};
#define REGISTER_PRODUCT(type) \
namespace { \
struct type##Register { \
type##Register() { \
Factory::Register(#type, []{ return new type(); }); \
} \
} type##_register; \
}
2.3 多态工厂(Polymorphic Factory)
多态工厂将工厂本身也抽象为接口,允许运行时切换不同的工厂实现。这种变体在需要支持多种实现方案的框架中很常见。
典型实现结构:
cpp复制class IFactory {
public:
virtual ~IFactory() = default;
virtual std::unique_ptr<IProduct> Create() = 0;
};
class ConcreteFactoryA : public IFactory {
public:
std::unique_ptr<IProduct> Create() override {
return std::make_unique<ProductA>();
}
};
class ConcreteFactoryB : public IFactory {
public:
std::unique_ptr<IProduct> Create() override {
return std::make_unique<ProductB>();
}
};
使用场景:
- 跨平台实现(不同平台使用不同工厂)
- 动态策略切换(根据配置选择不同工厂)
- 测试模拟(使用Mock工厂替代真实工厂)
3. 高级变体与模式组合
3.1 原型工厂(Prototype Factory)
原型工厂结合了原型模式,通过克隆现有对象来创建新对象,避免了重复初始化开销。
实现示例:
cpp复制class PrototypeFactory {
std::unordered_map<std::string, std::unique_ptr<BaseProduct>> prototypes_;
public:
void Register(const std::string& name, std::unique_ptr<BaseProduct> proto) {
prototypes_[name] = std::move(proto);
}
std::unique_ptr<BaseProduct> Create(const std::string& name) {
auto it = prototypes_.find(name);
return it != prototypes_.end() ? it->second->Clone() : nullptr;
}
};
适用场景:
- 对象创建成本高但克隆成本低
- 需要基于现有对象微调创建新对象
- 动态运行时配置对象属性
3.2 惰性工厂(Lazy Factory)
惰性工厂延迟对象的实际创建直到第一次使用时,结合了惰性初始化和工厂模式的特点。
实现方式:
cpp复制template <typename Product>
class LazyFactory {
std::function<std::unique_ptr<Product>()> creator_;
mutable std::unique_ptr<Product> instance_;
public:
explicit LazyFactory(std::function<std::unique_ptr<Product>()> creator)
: creator_(std::move(creator)) {}
Product* Get() const {
if (!instance_) {
instance_ = creator_();
}
return instance_.get();
}
};
优势:
- 节省资源,只有真正使用时才创建对象
- 可与其他模式(如单例)结合使用
- 特别适合重量级资源的创建管理
3.3 组合工厂(Composite Factory)
组合工厂将多个工厂组合起来,提供统一的创建接口。这种变体在微服务架构或模块化系统中很常见。
典型实现:
cpp复制class CompositeFactory : public IFactory {
std::vector<std::shared_ptr<IFactory>> factories_;
public:
void AddFactory(std::shared_ptr<IFactory> factory) {
factories_.push_back(std::move(factory));
}
std::unique_ptr<IProduct> Create() override {
for (auto& factory : factories_) {
if (auto product = factory->Create()) {
return product;
}
}
return nullptr;
}
};
使用模式:
- 责任链模式:按顺序尝试各个工厂
- 优先级策略:为工厂分配优先级
- 回退机制:主工厂失败后尝试备用工厂
4. 现代C++中的工厂模式演进
4.1 使用智能指针的工厂
现代C++推荐使用智能指针管理资源,工厂模式也需要相应调整:
cpp复制class SmartFactory {
public:
std::unique_ptr<Product> CreateUnique() {
return std::make_unique<ConcreteProduct>();
}
std::shared_ptr<Product> CreateShared() {
return std::make_shared<ConcreteProduct>();
}
};
注意事项:
- 优先使用make_unique/make_shared而非new
- 考虑使用enable_shared_from_this处理特殊情况
- 注意循环引用问题,必要时使用weak_ptr
4.2 可变参数工厂
C++11引入的可变参数模板使工厂接口更加灵活:
cpp复制template <typename Base, typename... Args>
class VariadicFactory {
public:
template <typename Derived>
static std::unique_ptr<Base> Create(Args&&... args) {
return std::make_unique<Derived>(std::forward<Args>(args)...);
}
};
优势:
- 支持任意数量和类型的构造参数
- 完美转发保持参数的值类别
- 编译时参数检查更安全
4.3 基于Concept的工厂
C++20引入的Concept可以强化工厂的类型约束:
cpp复制template <typename T>
concept Product = requires {
typename T::product_category;
{ T::Validate() } -> std::same_as<bool>;
};
template <Product P>
class ConceptFactory {
public:
static auto Create() {
static_assert(P::Validate(), "Invalid product type");
return new P();
}
};
改进点:
- 编译期明确的接口约束
- 更友好的错误信息
- 增强API文档性
5. 性能考量与优化策略
5.1 工厂对象缓存
频繁创建销毁工厂对象可能带来性能开销,可以考虑缓存策略:
cpp复制class CachedFactory {
using Creator = std::function<std::unique_ptr<Product>()>;
std::map<std::string, Creator> creators_;
std::map<std::string, std::unique_ptr<Product>> cache_;
public:
void Register(const std::string& name, Creator creator) {
creators_[name] = std::move(creator);
}
Product* Get(const std::string& name) {
auto& entry = cache_[name];
if (!entry && creators_.count(name)) {
entry = creators_[name]();
}
return entry.get();
}
};
优化点:
- 懒加载减少启动开销
- 对象复用避免重复创建
- 可扩展为LRU缓存等高级策略
5.2 多线程安全实现
线程安全的工厂需要考虑以下方面:
cpp复制class ThreadSafeFactory {
std::mutex mutex_;
std::map<std::string, std::shared_ptr<Product>> products_;
public:
std::shared_ptr<Product> Get(const std::string& name) {
std::lock_guard lock(mutex_);
auto& product = products_[name];
if (!product) {
product = std::make_shared<ConcreteProduct>();
}
return product;
}
};
关键点:
- 使用mutex保护共享状态
- 考虑双重检查锁定模式优化
- 避免在锁内执行耗时操作
- 可使用std::call_once保证单次初始化
5.3 内存池集成
对于高频创建的小对象,可结合内存池提升性能:
cpp复制template <typename T>
class PooledFactory {
ObjectPool<T> pool_;
public:
template <typename... Args>
T* Create(Args&&... args) {
return pool_.Construct(std::forward<Args>(args)...);
}
void Recycle(T* obj) {
pool_.Destroy(obj);
}
};
优势:
- 减少内存分配开销
- 提高缓存局部性
- 避免内存碎片
- 特别适合游戏等实时系统
6. 测试与模拟技巧
6.1 工厂的单元测试
测试工厂模式时需关注:
cpp复制TEST(FactoryTest, CreatesCorrectType) {
auto product = Factory::Create("ConcreteProduct");
ASSERT_NE(product, nullptr);
EXPECT_NE(dynamic_cast<ConcreteProduct*>(product.get()), nullptr);
}
TEST(FactoryTest, HandlesUnknownType) {
EXPECT_EQ(Factory::Create("UnknownType"), nullptr);
}
测试要点:
- 验证返回类型正确性
- 测试错误处理路径
- 检查资源管理情况
- 考虑边界条件
6.2 使用Mock工厂
在测试中使用Mock工厂隔离依赖:
cpp复制class MockFactory : public IFactory {
public:
MOCK_METHOD(std::unique_ptr<IProduct>, Create, (), (override));
};
TEST(ConsumerTest, UsesFactoryCorrectly) {
MockFactory factory;
EXPECT_CALL(factory, Create())
.WillOnce(Return(std::make_unique<MockProduct>()));
Consumer consumer(&factory);
consumer.DoSomething();
}
最佳实践:
- 使用GMock等框架简化Mock创建
- 验证工厂调用预期
- 控制Mock对象行为
- 测试异常场景
6.3 基准测试策略
对工厂实现进行性能评估:
cpp复制static void BM_FactoryCreate(benchmark::State& state) {
Factory factory;
for (auto _ : state) {
auto product = factory.Create();
benchmark::DoNotOptimize(product);
}
}
BENCHMARK(BM_FactoryCreate);
测量指标:
- 单次创建耗时
- 多线程竞争下的吞吐量
- 内存分配情况
- 缓存效率
7. 实际应用案例分析
7.1 游戏开发中的对象创建
游戏引擎典型应用:
cpp复制class GameObjectFactory {
std::map<std::string, std::function<GameObject*(const Properties&)>> creators_;
public:
template <typename T>
void Register(const std::string& type) {
creators_[type] = [](const Properties& props) {
auto obj = new T();
obj->Load(props);
return obj;
};
}
GameObject* Spawn(const std::string& type, const Properties& props) {
return creators_.at(type)(props);
}
};
设计考量:
- 支持热加载新游戏对象类型
- 与序列化系统集成
- 处理对象依赖关系
- 内存管理策略
7.2 GUI框架中的控件创建
GUI框架示例:
cpp复制class WidgetFactory {
public:
virtual std::unique_ptr<Button> CreateButton() = 0;
virtual std::unique_ptr<Menu> CreateMenu() = 0;
// ...其他控件接口
};
class WindowsFactory : public WidgetFactory {
std::unique_ptr<Button> CreateButton() override {
return std::make_unique<WindowsButton>();
}
// ...其他平台特定实现
};
关键点:
- 跨平台抽象
- 风格一致性维护
- 资源管理
- 事件处理集成
7.3 插件系统实现
插件架构示例:
cpp复制class PluginFactory {
struct PluginInfo {
std::string name;
std::function<std::unique_ptr<Plugin>()> creator;
};
std::vector<PluginInfo> plugins_;
public:
void LoadFromFolder(const std::string& path) {
// 动态加载DLL/SO并注册插件
}
std::vector<std::string> ListPlugins() const {
std::vector<std::string> names;
for (const auto& info : plugins_) {
names.push_back(info.name);
}
return names;
}
std::unique_ptr<Plugin> Create(const std::string& name) const {
for (const auto& info : plugins_) {
if (info.name == name) {
return info.creator();
}
}
return nullptr;
}
};
实现要点:
- 动态库加载机制
- 插件生命周期管理
- 版本兼容处理
- 安全隔离考虑
8. 反模式与常见陷阱
8.1 过度设计的工厂
常见问题表现:
- 为简单对象创建复杂工厂层次
- 过早引入工厂导致不必要抽象
- 工厂接口过于通用失去类型安全
解决方案:
- 遵循YAGNI原则
- 从简单工厂开始,按需演进
- 评估引入工厂的实际收益
8.2 循环依赖问题
典型场景:
- 工厂依赖具体产品类
- 产品类又依赖工厂
- 导致编译或链接错误
破解方法:
- 使用前向声明
- 引入抽象接口层
- 依赖注入解耦
- 考虑单例或全局访问点
8.3 对象生命周期管理混乱
常见错误:
- 原始指针与智能指针混用
- 工厂创建但外部释放责任不清
- 多工厂实例管理同一对象
最佳实践:
- 明确所有权策略
- 统一使用智能指针
- 文档化生命周期约定
- 使用RAII包装器
9. 扩展思考与进阶方向
9.1 依赖注入框架集成
现代DI框架如Boost.DI与工厂模式的结合:
cpp复制auto injector = boost::di::make_injector(
boost::di::bind<IService>.to<ServiceImpl>(),
boost::di::bind<IFactory>.to<ConcreteFactory>()
);
auto factory = injector.create<std::unique_ptr<IFactory>>();
优势:
- 自动解决依赖关系
- 配置集中管理
- 便于测试替换
- 支持作用域控制
9.2 编译期工厂探索
利用constexpr和模板元编程实现编译期工厂:
cpp复制template <typename... Products>
class CompileTimeFactory {
template <typename T>
static constexpr auto CreateImpl() {
static_assert((std::is_same_v<T, Products> || ...),
"Unsupported product type");
return T{};
}
public:
template <typename T>
static constexpr auto Create() {
return CreateImpl<T>();
}
};
适用场景:
- 嵌入式系统等资源受限环境
- 实时性要求极高的场景
- 作为运行时工厂的补充
9.3 函数式风格工厂
使用C++函数式特性实现更灵活的工厂:
cpp复制auto makeProductFactory(const Config& config) {
return [config](const Params& params) -> std::unique_ptr<Product> {
if (config.useNewAlgorithm) {
return std::make_unique<NewProduct>(params);
}
return std::make_unique<LegacyProduct>(params);
};
}
特点:
- 工厂作为一等公民
- 支持闭包捕获上下文
- 便于组合和转换
- 更简洁的实现方式
