1. 工厂模式在C++中的核心价值
工厂模式本质上是一种创建型设计模式,它解决了对象创建过程中的两个关键痛点:一是将对象的创建与使用解耦,二是为复杂对象的创建提供统一入口。在C++这种强类型语言中,工厂模式的应用比动态语言更具实际意义。
举个例子,假设我们正在开发一个跨平台的图形界面库,需要创建不同操作系统下的窗口对象。没有工厂模式时,代码中会散落着各种平台相关的条件判断:
cpp复制// 反例:直接创建对象
Window* createWindow() {
#ifdef WIN32
return new Win32Window();
#elif defined(MACOS)
return new MacWindow();
#else
return new LinuxWindow();
#endif
}
这种写法至少有三大问题:一是违反开闭原则,新增平台需要修改现有代码;二是创建逻辑分散难以维护;三是客户端代码与具体实现类耦合。而工厂模式通过引入抽象层完美解决了这些问题。
2. 基础工厂模式的三种实现变体
2.1 简单工厂模式
简单工厂是最基础的实现形式,通过一个静态方法封装对象创建逻辑:
cpp复制class WindowFactory {
public:
static Window* createWindow(WindowType type) {
switch(type) {
case WIN32: return new Win32Window();
case MACOS: return new MacWindow();
case LINUX: return new LinuxWindow();
default: throw std::runtime_error("Unsupported window type");
}
}
};
虽然简单,但这种实现存在明显局限——新增类型仍需修改工厂类。适用于对象类型稳定、变化较少的场景。
2.2 工厂方法模式
工厂方法将对象创建延迟到子类实现,符合开闭原则:
cpp复制class WindowFactory {
public:
virtual Window* createWindow() = 0;
};
class Win32WindowFactory : public WindowFactory {
public:
Window* createWindow() override { return new Win32Window(); }
};
// 使用时
WindowFactory* factory = new Win32WindowFactory();
Window* window = factory->createWindow();
这种模式的代价是需要为每个产品创建对应的工厂类,适合产品族扩展频繁但单个产品内部结构稳定的场景。
2.3 抽象工厂模式
当需要创建多个相关联的产品时,抽象工厂展现出独特优势。例如在游戏开发中,不同风格的UI组件需要配套创建:
cpp复制class UIFactory {
public:
virtual Button* createButton() = 0;
virtual Menu* createMenu() = 0;
};
class ModernUIFactory : public UIFactory {
Button* createButton() override { return new ModernButton(); }
Menu* createMenu() override { return new ModernMenu(); }
};
class ClassicUIFactory : public UIFactory {
Button* createButton() override { return new ClassicButton(); }
Menu* createMenu() override { return new ClassicMenu(); }
};
3. 现代C++中的工厂模式进阶技巧
3.1 使用智能指针管理对象生命周期
原始指针在工厂模式中容易引发内存泄漏。C++11后应优先使用智能指针:
cpp复制std::unique_ptr<Window> WindowFactory::createWindow() {
return std::make_unique<Win32Window>();
}
// 调用方无需手动delete
auto window = factory->createWindow();
3.2 模板工厂实现编译时多态
结合模板可以实现更灵活的工厂:
cpp复制template <typename T>
class GenericFactory {
public:
template <typename... Args>
static auto create(Args&&... args) {
return std::make_unique<T>(std::forward<Args>(args)...);
}
};
// 使用示例
auto widget = GenericFactory<Button>::create("Click me");
3.3 基于function的运行时工厂注册
实现插件系统时,需要动态注册工厂函数:
cpp复制class PluginFactory {
using Creator = std::function<std::unique_ptr<Plugin>()>;
std::unordered_map<std::string, Creator> creators_;
public:
void registerCreator(const std::string& name, Creator creator) {
creators_[name] = creator;
}
auto create(const std::string& name) {
return creators_.at(name)();
}
};
// 注册插件
factory.registerCreator("audio", []{ return std::make_unique<AudioPlugin>(); });
4. 工厂模式在大型项目中的实战应用
4.1 对象池与工厂的结合
在高性能场景中,对象池可以复用已创建的对象:
cpp复制class WindowPool {
std::stack<std::unique_ptr<Window>> pool_;
WindowFactory& factory_;
public:
Window* acquire() {
if(pool_.empty()) return factory_.createWindow();
auto obj = std::move(pool_.top());
pool_.pop();
return obj.release();
}
void release(Window* window) {
pool_.push(std::unique_ptr<Window>(window));
}
};
4.2 依赖注入框架中的工厂
现代DI框架如Boost.DI内部大量使用工厂模式:
cpp复制auto injector = di::make_injector(
di::bind<Window>().to<Win32Window>(),
di::bind<Button>().to<ModernButton>()
);
// 自动解析依赖并创建对象
auto window = injector.create<std::unique_ptr<Window>>();
4.3 原型模式与工厂的混合使用
当对象创建成本很高时,可以先克隆原型:
cpp复制class PrototypeFactory {
std::unordered_map<std::string, std::unique_ptr<Window>> prototypes_;
public:
void registerPrototype(const std::string& name, std::unique_ptr<Window> proto) {
prototypes_[name] = std::move(proto);
}
std::unique_ptr<Window> create(const std::string& name) {
return prototypes_[name]->clone();
}
};
5. 工厂模式的性能优化策略
5.1 对象创建的性能瓶颈分析
使用Benchmark工具测试不同实现方式的性能差异:
cpp复制static void BM_FactoryCreate(benchmark::State& state) {
WindowFactory factory;
for (auto _ : state) {
auto window = factory.createWindow();
delete window;
}
}
BENCHMARK(BM_FactoryCreate);
5.2 内存预分配技术
对于频繁创建销毁的小对象,可以使用内存池:
cpp复制class PooledWindowFactory {
boost::object_pool<Window> pool_;
public:
Window* createWindow() {
return pool_.construct();
}
void destroyWindow(Window* window) {
pool_.destroy(window);
}
};
5.3 线程安全的工厂实现
多线程环境下需要保证工厂的线程安全:
cpp复制class ThreadSafeFactory {
std::mutex mutex_;
std::unordered_map<std::string, Creator> creators_;
public:
void registerCreator(const std::string& name, Creator creator) {
std::lock_guard lock(mutex_);
creators_[name] = creator;
}
auto create(const std::string& name) {
std::lock_guard lock(mutex_);
return creators_.at(name)();
}
};
6. 工厂模式的典型误用与规避方案
6.1 过度设计陷阱
不是所有场景都需要工厂模式。当满足以下条件时才应考虑使用:
- 对象创建逻辑复杂
- 需要支持多种产品变体
- 需要解耦创建和使用
- 需要集中管理对象生命周期
6.2 循环依赖问题
当工厂与产品相互引用时会导致编译错误:
cpp复制// 错误示例
class Product {
Factory& factory_; // 循环依赖
};
class Factory {
Product* createProduct(); // 需要前置声明
};
解决方案是使用抽象接口或依赖注入。
6.3 类型擦除的代价
基于void*或基类的工厂会丢失类型信息:
cpp复制// 不推荐做法
class AnyFactory {
public:
void* create(const std::string& type);
};
应优先使用模板或明确的接口继承。
7. 工厂模式在现代C++框架中的应用实例
7.1 Qt框架中的对象树机制
Qt的QObject构造函数自动将对象加入父对象的孩子列表,本质上是一种工厂模式:
cpp复制QWidget* window = new QWidget();
QPushButton* button = new QPushButton("OK", window); // 自动成为window的子对象
7.2 Unreal Engine的UObject系统
UE4通过宏实现自动注册工厂:
cpp复制UCLASS()
class UMyObject : public UObject {
GENERATED_BODY()
};
// 使用时
UMyObject* obj = NewObject<UMyObject>();
7.3 LLVM中的Pass管理器
LLVM编译器使用工厂模式创建优化pass:
cpp复制void registerPass(const PassInfo& PI) {
PassRegistry::getPassRegistry()->registerPass(PI);
}
// 注册示例
static RegisterPass<MyPass> X("my-pass", "My optimization pass");
8. 工厂模式的未来演进方向
8.1 编译期工厂与constexpr
C++20引入的consteval可以实现编译期工厂:
cpp复制consteval auto makeWindow(WindowType type) {
if (type == WindowType::Main) return MainWindow{};
else return DialogWindow{};
}
// 编译期创建对象
constexpr auto window = makeWindow(WindowType::Main);
8.2 基于概念的工厂接口
C++20概念可以约束工厂产品类型:
cpp复制template <typename T>
concept Window = requires(T t) {
{ t.show() } -> std::same_as<void>;
{ t.hide() } -> std::same_as<void>;
};
template <Window W>
class WindowFactory {
public:
W create();
};
8.3 反射支持下的动态工厂
未来的C++反射提案可能简化工厂实现:
cpp复制std::meta::type_descriptor desc = reflexpr(MyClass);
auto obj = desc.construct();
