一.意图
抽象工厂是一种创造性设计模式,允许你生成相关对象的族,而无需指定具体类别。
在软件系统中,经常面临着"一系列相互依赖的对象"的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作。
提供一个接口,让该接口负责创建一系列"相关或者相互依赖的对象",无需指定它们具体的类。------《设计模式》GoF
二.问题
想象你正在创建一个家具店模拟器。你的代码由代表以下类型的类组成:
-
一组相关产品,比如:Chair+ Sofa+ CoffeeTable。
-
该家族的多个变体。例如,以下变体中有 Chair+ Sofa+ CoffeeTable 的乘积:Modern,Victorian ,ArtDeco ,

你需要一种方法来创建单个家具物件,使它们能与同类物品匹配。顾客收到不匹配的家具时会非常生气。

另外,添加新产品或产品系列时,你不应该更改现有代码。家具供应商经常更新目录,你不想每次都更改核心代码。
三.解决方案
抽象工厂模式首先建议为产品系列中的每个不同产品(如椅子、沙发或咖啡桌)明确声明接口。然后你可以让所有产品变体都遵循这些接口。例如,所有椅子变体都可以实现该接口;所有咖啡桌变体都能实现该接口,依此类推。

下一步是声明抽象工厂 ------一个接口,包含所有属于产品家族的产品(例如createChair,createSofa和createCoffeeTable)的创建方法列表。这些方法必须返回由我们之前提取的接口所代表的抽象产品类型:Chair、Sofa、CoffeeTable等等

那么,产品变体呢?对于产品家族的每个变体,我们基于接口创建一个独立的工厂类。工厂是返回特定类型产品的类。
客户端代码必须通过工厂和产品各自的抽象接口工作。这样你可以更改传递给客户端代码的工厂类型,以及客户端代码接收的产品变体,而不破坏实际客户端代码。
假设客户想要一家工厂来生产椅子。客户不必知道工厂的等级,也不管买什么椅子。无论是现代型还是维多利亚风格的椅子,客户都必须以相同的方式对待所有椅子,使用抽象界面。通过这种方法,客户对椅子唯一知道的就是它以某种方式实现了该方法。此外,无论退回哪种椅子,它都会与同一工厂生产的沙发或咖啡桌类型相匹配。
还有一点需要澄清:如果客户端只暴露在抽象界面上,实际的工厂对象是由什么创建的?通常,应用程序在初始化阶段创建一个具体的工厂对象。在此之前,应用必须根据配置或环境设置选择出厂类型。
四.模式结构

五.适合应用场景
-
当你的代码需要与各种相关产品家族兼容,但又不希望它依赖于这些产品的具体类时,可以使用抽象工厂------这些类别可能事先未知,或者你只是想为未来的扩展性留出空间。
抽象工厂为你提供了一个界面,用于创建产品家族中每个类别的对象。只要你的代码通过这个界面创建对象,你就不用担心生成与应用已创建产品不匹配的错误变体。
-
当你有一个包含一组工厂方法、模糊其主要职责的类时,考虑实现抽象工厂。
在设计良好的项目中,每个班级只负责一件事。当一个类处理多种产品类型时,可能值得将其工厂方法提取成独立的工厂类或完整的抽象工厂实现。
六.实现方式
-
绘制出不同产品类型与这些产品的变体矩阵。
-
为所有产品类型声明抽象产品接口。然后让所有具体的产品类实现这些接口。
-
声明抽象工厂接口,包含一组创建方法,适用于所有抽象产品。
-
实现一套具体的工厂类,每个产品变体对应一个。
-
在应用里某个地方创建出厂初始化代码。它应该实例化一个具体工厂类,具体取决于应用配置或当前环境。将这个工厂对象传递给所有构建产品的类。
-
扫描代码,找到所有直接调用产品构造子。用调用工厂对象上的相应创建方法替换它们。
七.优缺点
-
优点:
-
你可以放心,工厂里买到的产品彼此兼容。
-
你会避免具体产品和客户代码之间的紧密耦合。
-
单一责任原则。你可以把产品创建代码提取到一个地方,让代码更容易支持。
-
开闭原则。你可以在不破坏现有客户端代码的情况下引入新的产品变体。
-
-
缺点
- 代码可能会变得比应有的更复杂,因为会随着模式引入许多新的接口和类。
八.与其他模式的关系
-
许多设计从工厂方法开始(简单且通过子职业更可定制),随后逐步发展为抽象工厂、原型或建造者(更灵活但更复杂)。
-
Builder 专注于一步步构建复杂物体。Abstract Factory 专注于创建相关对象的族。抽象工厂会立即返回产品,而建造者允许你在取产品前运行一些额外的构建步骤。
-
抽象工厂类通常基于一组工厂方法,但你也可以用Prototype来组合这些类的方法。
-
当你只想隐藏子系统对象的创建方式,Abstract Factory 可以作为 Facade 的替代方案。
-
你可以同时使用抽象工厂和桥。这种配对在桥定义的某些抽象只能对特定实现有效时非常有用。在这种情况下,抽象工厂可以封装这些关系,并向客户端代码隐藏复杂性。
-
抽象工厂、建造者和原型都可以作为单例实现。
九.示例代码
#include <iostream>
#include <string>
using namespace std;
// ====================== 1. 抽象产品层:定义产品公共接口 ======================
// 抽象产品1:手机
class Phone {
public:
// 纯虚函数,定义手机的核心功能
virtual void showBrand() const = 0;
// 虚析构函数,防止子类内存泄漏
virtual ~Phone() = default;
};
// 抽象产品2:路由器
class Router {
public:
virtual void showBrand() const = 0;
virtual ~Router() = default;
};
// ====================== 2. 具体产品层:实现抽象产品接口 ======================
// 具体产品:小米手机(属于小米产品族)
class XiaoMiPhone : public Phone {
public:
void showBrand() const override {
cout << "我是【小米手机】,属于小米产品族" << endl;
}
};
// 具体产品:小米路由器(属于小米产品族)
class XiaoMiRouter : public Router {
public:
void showBrand() const override {
cout << "我是【小米路由器】,属于小米产品族" << endl;
}
};
// 具体产品:华为手机(属于华为产品族)
class HuaWeiPhone : public Phone {
public:
void showBrand() const override {
cout << "我是【华为手机】,属于华为产品族" << endl;
}
};
// 具体产品:华为路由器(属于华为产品族)
class HuaWeiRouter : public Router {
public:
void showBrand() const override {
cout << "我是【华为路由器】,属于华为产品族" << endl;
}
};
// ====================== 3. 抽象工厂层:声明创建产品族的接口 ======================
// 抽象工厂:电子产品工厂,约定生产【手机+路由器】这一族产品
class ElectronicFactory {
public:
// 生产手机的抽象方法
virtual Phone* createPhone() const = 0;
// 生产路由器的抽象方法
virtual Router* createRouter() const = 0;
// 虚析构函数
virtual ~ElectronicFactory() = default;
};
// ====================== 4. 具体工厂层:实现抽象工厂,生产对应产品族 ======================
// 具体工厂:小米工厂,只生产小米产品族的所有产品
class XiaoMiFactory : public ElectronicFactory {
public:
Phone* createPhone() const override {
return new XiaoMiPhone();
}
Router* createRouter() const override {
return new XiaoMiRouter();
}
};
// 具体工厂:华为工厂,只生产华为产品族的所有产品
class HuaWeiFactory : public ElectronicFactory {
public:
Phone* createPhone() const override {
return new HuaWeiPhone();
}
Router* createRouter() const override {
return new HuaWeiRouter();
}
};
// ====================== 客户端测试代码 ======================
void client(const ElectronicFactory* factory) {
// 由工厂统一创建产品,客户端**无需关心具体产品类名**
Phone* phone = factory->createPhone();
Router* router = factory->createRouter();
// 使用产品
phone->showBrand();
router->showBrand();
// 释放资源
delete phone;
delete router;
}
int main() {
cout << "===== 生产小米产品族 =====" << endl;
ElectronicFactory* miFactory = new XiaoMiFactory();
client(miFactory);
cout << "\n===== 生产华为产品族 =====" << endl;
ElectronicFactory* hwFactory = new HuaWeiFactory();
client(hwFactory);
// 释放工厂资源
delete miFactory;
delete hwFactory;
return 0;
}
执行结果
===== 生产小米产品族 =====
我是【小米手机】,属于小米产品族
我是【小米路由器】,属于小米产品族
===== 生产华为产品族 =====
我是【华为手机】,属于华为产品族
我是【华为路由器】,属于华为产品族