1. 什么是工厂模式?为什么需要它? 核心思想 :工厂模式是一种创建型设计模式,其核心思想是将对象的创建过程封装起来 。客户端(使用对象的代码)不再直接使用 new 关键字来创建具体类的实例,而是向一个“工厂”请求一个对象,由工厂来决定到底创建哪个具体类的实例。
解决的问题 : 想象一下,如果没有工厂模式,你的代码可能会是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 void some_function (const std::string& shapeType) { Shape* shape = nullptr ; if (shapeType == "Circle" ) { shape = new Circle (); } else if (shapeType == "Square" ) { shape = new Square (); } else if (shapeType == "Triangle" ) { shape = new Triangle (); } if (shape) { shape->draw (); delete shape; } }
这段代码有几个严重的问题:
紧密耦合 :客户端代码 some_function 与具体的 Circle, Square, Triangle 类紧密地耦合在一起。如果未来要增加一个新的形状,比如 Rectangle,你必须修改 some_function 函数,在 if-else 链中增加一个分支。这违反了开闭原则 (对扩展开放,对修改关闭)。
创建逻辑重复 :如果系统中有多个地方需要根据类型创建形状,那么这段 if-else 逻辑就会在各处重复出现,难以维护。
创建过程复杂 :如果创建某个对象的过程非常复杂(例如,需要读取配置文件、进行复杂的初始化等),这些复杂的逻辑会散布在客户端代码中,使其变得混乱。
工厂模式的目标 就是将这种对象的创建逻辑从客户端代码中分离出来,集中到一个地方进行管理,从而实现解耦 、封装 和可维护性 。
2. 工厂模式的分类 通常,我们将工厂模式分为三种类型,它们在复杂度和灵活性上层层递进:
简单工厂模式 (Simple Factory Pattern) - 最简单,但不属于 GoF(《设计模式》)的 23 种标准设计模式之一,但非常常用。
工厂方法模式 (Factory Method Pattern) - GoF 标准模式之一,解决了简单工厂的扩展性问题。
抽象工厂模式 (Abstract Factory Pattern) - GoF 标准模式之一,用于创建一系列相关的对象(产品族)。
下面我们逐一详细讲解。
3. 简单工厂模式 (Simple Factory Pattern) 定义 :定义一个工厂类,它可以根据传入的参数来动态决定应该创建哪一个产品类的实例。
结构 :
Factory (工厂类) :负责实现创建所有实例的内部逻辑。
Product (抽象产品) :定义了所有具体产品需要实现的接口(在 C++ 中通常是抽象基类)。
ConcreteProduct (具体产品) :实现了 Product 接口的具体类,是工厂创建的目标。
C++ 示例 :
我们用一个制作不同类型咖啡的例子来说明。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 #include <iostream> #include <string> #include <memory> class Coffee {public : virtual ~Coffee () = default ; virtual void show () const = 0 ; }; class Americano : public Coffee {public : void show () const override { std::cout << "一杯美式咖啡" << std::endl; } }; class Latte : public Coffee {public : void show () const override { std::cout << "一杯拿铁咖啡" << std::endl; } }; class CoffeeFactory {public : static std::unique_ptr<Coffee> createCoffee (const std::string& type) { if (type == "Americano" ) { return std::make_unique <Americano>(); } else if (type == "Latte" ) { return std::make_unique <Latte>(); } return nullptr ; } }; int main () { auto americano = CoffeeFactory::createCoffee ("Americano" ); if (americano) { americano->show (); } auto latte = CoffeeFactory::createCoffee ("Latte" ); if (latte) { latte->show (); } return 0 ; }
优点 :
封装 :将对象的创建逻辑封装在工厂类中,客户端代码只与工厂和抽象产品接口打交道,实现了客户端与具体产品的解耦。
简单直观 :结构简单,易于理解和实现。
缺点 :
违反开闭原则 :当需要增加一种新的咖啡类型时(例如 Cappuccino),必须修改 CoffeeFactory 类的 createCoffee 方法,在 if-else 中增加一个新的分支。这不符合“对修改关闭”的原则。
职责过重 :所有的产品创建逻辑都集中在一个工厂类中,如果产品种类非常多,这个工厂类会变得非常庞大和臃肿。
应用场合 :
当需要创建的对象较少,且不经常增加新产品时。
客户端不关心对象的创建过程,只关心如何使用。
4. 工厂方法模式 (Factory Method Pattern) 定义 :定义一个用于创建对象的接口(工厂方法),但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
结构 :
Product (抽象产品) :与简单工厂中的定义相同。
ConcreteProduct (具体产品) :与简单工厂中的定义相同。
Creator (抽象工厂) :声明一个 FactoryMethod,该方法返回一个 Product 类型的对象。
ConcreteCreator (具体工厂) :实现 FactoryMethod,负责创建并返回具体的 ConcreteProduct 实例。
C++ 示例 :
这次,我们让每个咖啡店(具体工厂)自己决定制作哪种咖啡。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 #include <iostream> #include <string> #include <memory> class Coffee {public : virtual ~Coffee () = default ; virtual void show () const = 0 ; }; class Americano : public Coffee {public : void show () const override { std::cout << "一杯美式咖啡" << std::endl; } }; class Latte : public Coffee {public : void show () const override { std::cout << "一杯拿铁咖啡" << std::endl; } }; class CoffeeFactory {public : virtual ~CoffeeFactory () = default ; virtual std::unique_ptr<Coffee> createCoffee () const = 0 ; void serveCoffee () const { auto coffee = createCoffee (); std::cout << "为您准备好了: " ; coffee->show (); } }; class AmericanoFactory : public CoffeeFactory {public : std::unique_ptr<Coffee> createCoffee () const override { return std::make_unique <Americano>(); } }; class LatteFactory : public CoffeeFactory {public : std::unique_ptr<Coffee> createCoffee () const override { return std::make_unique <Latte>(); } }; int main () { auto americano_factory = std::make_unique <AmericanoFactory>(); americano_factory->serveCoffee (); auto latte_factory = std::make_unique <LatteFactory>(); latte_factory->serveCoffee (); class Cappuccino : public Coffee { public : void show () const override { std::cout << "一杯卡布奇诺" << std::endl; } }; class CappuccinoFactory : public CoffeeFactory { public : std::unique_ptr<Coffee> createCoffee () const override { return std::make_unique <Cappuccino>(); } }; auto cappuccino_factory = std::make_unique <CappuccinoFactory>(); cappuccino_factory->serveCoffee (); return 0 ; }
优点 :
遵循开闭原则 :当需要添加新产品时,只需添加一个新的具体产品类和一个新的具体工厂类,而无需修改任何现有代码。这使得系统扩展性极佳。
职责单一 :每个具体工厂只负责创建一个具体产品,符合单一职责原则。
解耦 :客户端代码只依赖于抽象工厂和抽象产品,与具体实现无关。
缺点 :
类的数量增加 :每增加一个产品,就需要增加一个对应的具体工厂类,这会使得系统中的类数量成倍增加,增加了系统的复杂度和代码量。
应用场合 :
当一个类不知道它所需要的对象的具体类型时(例如,一个框架需要创建由其用户自定义的组件)。
当一个类希望由它的子类来指定它所创建的对象时。
当你想为用户提供一个创建对象的接口,但又不希望暴露创建对象的具体细节时(例如,在库或框架开发中)。
5. 抽象工厂模式 (Abstract Factory Pattern) 定义 :提供一个接口,用于创建一系列相关或相互依赖的对象 (产品族),而无需指定它们具体的类。
核心区别 :工厂方法模式关注的是一个产品 的创建,而抽象工厂模式关注的是一个产品族 (多个不同类型但相互关联的产品)的创建。
结构 :
AbstractFactory (抽象工厂) :声明一组用于创建抽象产品的接口(例如 createProductA(), createProductB())。
ConcreteFactory (具体工厂) :实现 AbstractFactory 的接口,负责创建一组具体的产品。
AbstractProduct (抽象产品) :为一类产品对象声明一个接口(例如 ProductA, ProductB)。
ConcreteProduct (具体产品) :定义了由相应的具体工厂创建的具体产品对象。
C++ 示例 :
假设我们要创建一个跨平台的 GUI 库,它需要提供按钮(Button)和复选框(Checkbox)。我们希望它能同时支持 Windows 和 macOS 风格。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 #include <iostream> #include <string> #include <memory> class Button {public : virtual ~Button () = default ; virtual void paint () const = 0 ; }; class Checkbox {public : virtual ~Checkbox () = default ; virtual void check () const = 0 ; }; class WindowsButton : public Button {public : void paint () const override { std::cout << "渲染一个 Windows 风格的按钮" << std::endl; } }; class WindowsCheckbox : public Checkbox {public : void check () const override { std::cout << "勾选一个 Windows 风格的复选框" << std::endl; } }; class MacOSButton : public Button {public : void paint () const override { std::cout << "渲染一个 macOS 风格的按钮" << std::endl; } }; class MacOSCheckbox : public Checkbox {public : void check () const override { std::cout << "勾选一个 macOS 风格的复选框" << std::endl; } }; class GUIFactory {public : virtual ~GUIFactory () = default ; virtual std::unique_ptr<Button> createButton () const = 0 ; virtual std::unique_ptr<Checkbox> createCheckbox () const = 0 ; }; class WindowsFactory : public GUIFactory {public : std::unique_ptr<Button> createButton () const override { return std::make_unique <WindowsButton>(); } std::unique_ptr<Checkbox> createCheckbox () const override { return std::make_unique <WindowsCheckbox>(); } }; class MacOSFactory : public GUIFactory {public : std::unique_ptr<Button> createButton () const override { return std::make_unique <MacOSButton>(); } std::unique_ptr<Checkbox> createCheckbox () const override { return std::make_unique <MacOSCheckbox>(); } }; class Application {private : std::unique_ptr<GUIFactory> factory; std::unique_ptr<Button> button; std::unique_ptr<Checkbox> checkbox; public : explicit Application (std::unique_ptr<GUIFactory> f) : factory(std::move(f)) { } void createUI () { button = factory->createButton (); checkbox = factory->createCheckbox (); } void run () { button->paint (); checkbox->check (); } }; int main () { std::cout << "在 Windows 环境下运行:" << std::endl; auto win_factory = std::make_unique <WindowsFactory>(); Application app_win (std::move(win_factory)) ; app_win.createUI (); app_win.run (); std::cout << "\n切换到 macOS 环境运行:" << std::endl; auto mac_factory = std::make_unique <MacOSFactory>(); Application app_mac (std::move(mac_factory)) ; app_mac.createUI (); app_mac.run (); return 0 ; }
优点 :
隔离具体类 :客户端代码完全与具体产品实现分离,只依赖于抽象工厂和抽象产品接口。
易于切换产品族 :只需要改变具体工厂的实例,就可以轻松地切换整个产品族。在上面的例子中,从 Windows 风格切换到 macOS 风格只需要更换工厂对象。
保证产品兼容性 :由于一个具体工厂只创建属于同一产品族的产品,因此可以保证这些产品之间是相互兼容的。
缺点 :
难以扩展新的产品类型 :如果要在产品族中增加一个新的产品(例如,增加一个 TextField),那么需要修改抽象工厂 GUIFactory 的接口,这会导致所有具体工厂子类都需要进行修改,违反了开闭原则。
应用场合 :
当一个系统需要与多个产品系列中的一个系列进行配置时。
当系统要独立于其产品的创建、组合和表示时。
当你需要提供一个产品类库,而只想暴露它们的接口而不是实现时。
例如:更换数据库访问层(一个工厂用于 SQL Server,一个用于 Oracle),更换UI主题,支持不同的操作系统等。
6. 总结与对比
特性
简单工厂模式
工厂方法模式
抽象工厂模式
目的
封装单一产品的创建
封装单一产品的创建,但将决策延迟到子类
封装一个产品族的创建
复杂度
低
中
高
开闭原则
违反 (修改工厂类)
遵守 (添加新工厂)
遵守 (添加新产品族),违反 (添加新产品类型)
代码结构
一个工厂类,多个产品类
抽象工厂+具体工厂,抽象产品+具体产品
抽象工厂+具体工厂,多组抽象产品+具体产品
关注点
如何创建一个 产品
如何创建一个 产品
如何创建一组 产品
7. C++ 特有的考量
智能指针 :在 C++11 及以后的版本中,工厂方法返回对象时应优先使用智能指针(std::unique_ptr 或 std::shared_ptr)来管理对象的生命周期,避免内存泄漏。std::unique_ptr 通常是首选,因为它表达了所有权的唯一性,开销也更低。
模板元编程 :对于某些场景,可以使用模板来实现更泛化的工厂,减少手写具体工厂类的需要,但这会增加编译期复杂性。