1. 工厂模式在C++中的核心价值
工厂模式是面向对象设计中应用最广泛的设计模式之一,它解决了对象创建过程中的核心痛点。想象你正在开发一个图形编辑器,需要创建圆形、矩形、三角形等不同形状对象。最直接的做法可能是这样的:
cpp复制Shape* shape;
if (type == "circle") {
shape = new Circle();
} else if (type == "rectangle") {
shape = new Rectangle();
} // 更多判断...
这种写法存在几个明显问题:创建逻辑分散在各处难以维护;新增类型需要修改所有创建点;客户端代码与具体类耦合严重。工厂模式通过将对象创建过程封装到独立类中,完美解决了这些问题。
在C++中实现工厂模式有特殊考量:首先,C++没有Java/C#那样的反射机制,无法通过类名字符串直接创建对象;其次,C++需要显式管理内存,工厂对象生命周期与产品对象的归属关系需要仔细设计;再者,C++支持栈对象和堆对象两种创建方式,工厂实现上需要有所区分。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础工厂模式实现与演进
2.1 简单静态工厂
最简单的工厂实现是使用静态方法:
cpp复制class ShapeFactory {
public:
static Shape* create(const std::string& type) {
if (type == "circle") return new Circle();
if (type == "rectangle") return new Rectangle();
return nullptr;
}
};
这种实现虽然简单,但存在明显缺陷:每次新增类型都需要修改工厂类,违反开闭原则;创建逻辑集中在一个方法中会变得臃肿;无法利用多态特性进行扩展。
2.2 多态工厂模式
更优雅的实现是引入抽象工厂接口:
cpp复制class ShapeFactory {
public:
virtual ~ShapeFactory() = default;
virtual std::unique_ptr<Shape> create() const = 0;
};
class CircleFactory : public ShapeFactory {
public:
std::unique_ptr<Shape> create() const override {
return std::make_unique<Circle>();
}
};
这种实现将每个产品的创建逻辑封装到自己的工厂类中,符合单一职责原则。客户端代码通过工厂接口操作,与具体产品完全解耦:
cpp复制void render(const ShapeFactory& factory) {
auto shape = factory.create();
shape->draw();
}
3. 现代C++中的工厂模式变体
3.1 模板工厂
C++模板为工厂模式提供了新的可能性:
cpp复制template <typename T>
class GenericFactory {
public:
static std::unique_ptr<T> create() {
return std::make_unique<T>();
}
};
// 使用示例
auto circle = GenericFactory<Circle>::create();
模板工厂的优势在于编译时类型安全,避免了运行时类型检查的开销。结合可变参数模板,可以支持任意构造参数:
cpp复制template <typename T, typename... Args>
class VariadicFactory {
public:
static std::unique_ptr<T> create(Args&&... args) {
return std::make_unique<T>(std::forward<Args>(args)...);
}
};
3.2 函数对象工厂
C++11引入的lambda和std::function可以创建轻量级工厂:
cpp复制using ShapeFactoryFunc = std::function<std::unique_ptr<Shape>()>;
ShapeFactoryFunc circleFactory = [] {
return std::make_unique<Circle>();
};
// 注册到工厂映射表
std::map<std::string, ShapeFactoryFunc> factories;
factories["circle"] = circleFactory;
这种实现特别适合插件式架构,可以在运行时动态注册新的工厂函数。
3.3 原型模式工厂
结合原型模式,可以实现对象克隆工厂:
cpp复制class Prototype {
public:
virtual ~Prototype() = default;
virtual std::unique_ptr<Prototype> clone() const = 0;
};
class PrototypeFactory {
std::unordered_map<std::string, std::unique_ptr<Prototype>> prototypes;
public:
void registerPrototype(const std::string& id, std::unique_ptr<Prototype> proto) {
prototypes[id] = std::move(proto);
}
std::unique_ptr<Prototype> create(const std::string& id) const {
auto it = prototypes.find(id);
if (it != prototypes.end()) {
return it->second->clone();
}
return nullptr;
}
};
4. 工厂模式在C++项目中的实战应用
4.1 跨平台UI组件创建
在开发跨平台UI框架时,工厂模式可以优雅地处理不同平台下的控件创建:
cpp复制class Button {
public:
virtual void render() = 0;
virtual ~Button() = default;
};
class WinButton : public Button { /*...*/ };
class MacButton : public Button { /*...*/ };
class GUIFactory {
public:
virtual std::unique_ptr<Button> createButton() = 0;
};
class WinFactory : public GUIFactory {
public:
std::unique_ptr<Button> createButton() override {
return std::make_unique<WinButton>();
}
};
4.2 游戏开发中的对象池
游戏开发中常使用对象池优化性能,结合工厂模式可以这样实现:
cpp复制class GameObjectPool {
std::vector<std::unique_ptr<GameObject>> pool;
std::function<std::unique_ptr<GameObject>()> factory;
public:
GameObjectPool(std::function<std::unique_ptr<GameObject>()> f) : factory(f) {}
GameObject* acquire() {
if (pool.empty()) {
return factory().release();
}
auto obj = std::move(pool.back());
pool.pop_back();
return obj.release();
}
void release(GameObject* obj) {
pool.emplace_back(obj);
}
};
4.3 依赖注入框架
现代C++依赖注入框架通常基于工厂模式构建:
cpp复制class DIContainer {
std::map<std::type_index, std::function<std::any()>> factories;
public:
template <typename T>
void registerFactory(std::function<std::unique_ptr<T>()> f) {
factories[typeid(T)] = [f] { return f(); };
}
template <typename T>
std::unique_ptr<T> resolve() {
auto it = factories.find(typeid(T));
if (it != factories.end()) {
return std::any_cast<std::unique_ptr<T>>(it->second());
}
return nullptr;
}
};
5. 工厂模式的最佳实践与陷阱规避
5.1 内存管理策略
C++工厂面临的核心挑战是内存管理。以下是几种常见策略:
-
原始指针工厂:
cpp复制class RawPtrFactory { public: virtual Button* create() = 0; virtual ~RawPtrFactory() = default; };需要明确文档说明所有权转移规则,容易导致内存泄漏。
-
unique_ptr工厂(推荐):
cpp复制class UniquePtrFactory { public: virtual std::unique_ptr<Button> create() = 0; };明确表达所有权转移,现代C++首选方案。
-
shared_ptr工厂:
cpp复制class SharedPtrFactory { public: virtual std::shared_ptr<Button> create() = 0; };适用于需要共享所有权的场景,但可能引入循环引用。
5.2 异常安全考量
工厂方法可能抛出异常,需要确保资源安全:
cpp复制std::unique_ptr<Resource> createResource() {
auto part1 = std::make_unique<Part1>();
auto part2 = std::make_unique<Part2>(); // 可能抛出
return std::make_unique<Resource>(std::move(part1), std::move(part2));
}
使用RAII对象可以保证即使抛出异常也不会泄漏资源。
5.3 性能优化技巧
- 对象复用:对于创建成本高的对象,可以实现对象池工厂
- 局部静态工厂:对于无状态的工厂方法,可以使用Meyers' singleton模式
cpp复制Factory& getFactory() { static Factory instance; return instance; } - 热路径优化:在性能关键路径上,可以考虑使用模板元编程实现编译时工厂
6. C++20新特性对工厂模式的影响
6.1 概念(Concepts)约束工厂接口
C++20概念可以更好地约束工厂模板参数:
cpp复制template <typename T>
concept ShapeFactory = requires {
{ T::create() } -> std::convertible_to<std::unique_ptr<Shape>>;
};
template <ShapeFactory F>
void processShape() {
auto shape = F::create();
shape->draw();
}
6.2 协程工厂
C++20协程可以实现异步对象工厂:
cpp复制Generator<std::unique_ptr<Shape>> shapeGenerator() {
co_yield std::make_unique<Circle>();
co_yield std::make_unique<Rectangle>();
// ...
}
6.3 模块化工厂
C++20模块可以更好地封装工厂实现:
cpp复制// ShapeFactory.ixx
export module ShapeFactory;
export {
class ShapeFactory {
public:
virtual std::unique_ptr<Shape> create() = 0;
};
}
7. 工厂模式与其他模式的协同
7.1 工厂方法与策略模式结合
cpp复制class RenderingStrategy {
public:
virtual void render(Shape&) = 0;
};
class Shape {
std::unique_ptr<RenderingStrategy> strategy;
public:
void setStrategy(std::unique_ptr<RenderingStrategy> s) {
strategy = std::move(s);
}
void draw() { strategy->render(*this); }
};
class StrategyFactory {
public:
virtual std::unique_ptr<RenderingStrategy> createStrategy() = 0;
};
7.2 抽象工厂与建造者模式结合
复杂对象的创建可以结合两种模式:
cpp复制class UIBuilder {
public:
virtual void buildButton() = 0;
virtual void buildMenu() = 0;
virtual std::unique_ptr<UI> getResult() = 0;
};
class UIFactory {
public:
virtual std::unique_ptr<UIBuilder> createBuilder() = 0;
std::unique_ptr<UI> createUI() {
auto builder = createBuilder();
builder->buildButton();
builder->buildMenu();
return builder->getResult();
}
};
7.3 工厂与观察者模式集成
实现事件监听对象的创建:
cpp复制class EventListenerFactory {
public:
virtual std::unique_ptr<EventListener> createListener() = 0;
};
class EventManager {
std::vector<std::unique_ptr<EventListener>> listeners;
std::shared_ptr<EventListenerFactory> factory;
public:
void addNewListener() {
listeners.push_back(factory->createListener());
}
};
8. 测试驱动下的工厂模式实现
8.1 模拟对象工厂
在单元测试中,可以使用模拟工厂替换真实工厂:
cpp复制class MockShapeFactory : public ShapeFactory {
public:
MOCK_METHOD(std::unique_ptr<Shape>, create, (), (override));
};
TEST(ShapeTest, ShouldUseFactory) {
MockShapeFactory factory;
EXPECT_CALL(factory, create())
.WillOnce(Return(std::make_unique<MockCircle>()));
auto shape = factory.create();
shape->draw(); // 测试模拟对象行为
}
8.2 依赖注入测试
通过工厂接口注入测试依赖:
cpp复制class Processor {
std::shared_ptr<ServiceFactory> factory;
public:
Processor(std::shared_ptr<ServiceFactory> f) : factory(f) {}
void process() {
auto service = factory->create();
service->execute();
}
};
TEST(ProcessorTest, ShouldCallService) {
auto mockFactory = std::make_shared<MockServiceFactory>();
EXPECT_CALL(*mockFactory, create())
.WillOnce(Return(std::make_unique<MockService>()));
Processor processor(mockFactory);
processor.process(); // 验证是否调用了mock服务
}
9. 工厂模式在现代C++框架中的应用实例
9.1 Qt框架中的工厂模式
Qt广泛使用工厂方法创建控件和图形项:
cpp复制QGraphicsItem* ItemFactory::createItem(ItemType type) {
switch(type) {
case Rectangle: return new QGraphicsRectItem;
case Ellipse: return new QGraphicsEllipseItem;
// ...
}
}
9.2 Boost.DI中的类型工厂
Boost.DI使用高级工厂模式实现依赖注入:
cpp复制auto injector = di::make_injector(
di::bind<IService>.to<ServiceImpl>(),
di::bind<IFactory>.to(factoryCreator)
);
9.3 Unreal Engine的UObject工厂
Unreal引擎使用宏和模板实现对象工厂:
cpp复制UCLASS()
class UMyObject : public UObject {
GENERATED_BODY()
// ...
};
// 创建实例
UMyObject* obj = NewObject<UMyObject>();
10. 从工厂模式到对象创建的语言演进
C++本身也在不断发展对象创建机制:
-
统一初始化语法 (C++11):
cpp复制auto ptr = std::make_unique<MyClass>{arg1, arg2}; -
推导指南 (C++17):
cpp复制template <typename T> struct Factory { T operator()() const { return T{}; } }; Factory f{1}; // 推导为Factory<int> -
设计模式的语言内化:
未来C++可能会引入更直接的模式支持,如:cpp复制interface IFactory { Shape create() const; }
在实际项目中,我倾向于根据具体场景选择工厂实现:对于简单对象使用模板工厂,需要多态扩展时使用抽象工厂,涉及复杂初始化时结合建造者模式。一个常见误区是过度设计工厂层次,实际上对于大多数场景,一个简单的工厂函数可能就足够了。记住,设计模式是工具而非目标,简洁有效的解决方案才是最终追求。
