抽象工厂模式

一.意图

抽象工厂是一种创造性设计模式,允许你生成相关对象的族,而无需指定具体类别。

在软件系统中,经常面临着"一系列相互依赖的对象"的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作。

提供一个接口,让该接口负责创建一系列"相关或者相互依赖的对象",无需指定它们具体的类。------《设计模式》GoF

二.问题

想象你正在创建一个家具店模拟器。你的代码由代表以下类型的类组成:

  1. 一组相关产品,比如:Chair+ Sofa+ CoffeeTable。

  2. 该家族的多个变体。例如,以下变体中有 Chair+ Sofa+ CoffeeTable 的乘积:Modern,Victorian ,ArtDeco ,

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

另外,添加新产品或产品系列时,你不应该更改现有代码。家具供应商经常更新目录,你不想每次都更改核心代码。

三.解决方案

抽象工厂模式首先建议为产品系列中的每个不同产品(如椅子、沙发或咖啡桌)明确声明接口。然后你可以让所有产品变体都遵循这些接口。例如,所有椅子变体都可以实现该接口;所有咖啡桌变体都能实现该接口,依此类推。

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

那么,产品变体呢?对于产品家族的每个变体,我们基于接口创建一个独立的工厂类。工厂是返回特定类型产品的类。

客户端代码必须通过工厂和产品各自的抽象接口工作。这样你可以更改传递给客户端代码的工厂类型,以及客户端代码接收的产品变体,而不破坏实际客户端代码。

假设客户想要一家工厂来生产椅子。客户不必知道工厂的等级,也不管买什么椅子。无论是现代型还是维多利亚风格的椅子,客户都必须以相同的方式对待所有椅子,使用抽象界面。通过这种方法,客户对椅子唯一知道的就是它以某种方式实现了该方法。此外,无论退回哪种椅子,它都会与同一工厂生产的沙发或咖啡桌类型相匹配。

还有一点需要澄清:如果客户端只暴露在抽象界面上,实际的工厂对象是由什么创建的?通常,应用程序在初始化阶段创建一个具体的工厂对象。在此之前,应用必须根据配置或环境设置选择出厂类型。

四.模式结构

五.适合应用场景

  1. 当你的代码需要与各种相关产品家族兼容,但又不希望它依赖于这些产品的具体类时,可以使用抽象工厂------这些类别可能事先未知,或者你只是想为未来的扩展性留出空间。

    抽象工厂为你提供了一个界面,用于创建产品家族中每个类别的对象。只要你的代码通过这个界面创建对象,你就不用担心生成与应用已创建产品不匹配的错误变体。

  2. 当你有一个包含一组工厂方法、模糊其主要职责的类时,考虑实现抽象工厂。

    在设计良好的项目中,每个班级只负责一件事。当一个类处理多种产品类型时,可能值得将其工厂方法提取成独立的工厂类或完整的抽象工厂实现。

六.实现方式

  1. 绘制出不同产品类型与这些产品的变体矩阵。

  2. 为所有产品类型声明抽象产品接口。然后让所有具体的产品类实现这些接口。

  3. 声明抽象工厂接口,包含一组创建方法,适用于所有抽象产品。

  4. 实现一套具体的工厂类,每个产品变体对应一个。

  5. 在应用里某个地方创建出厂初始化代码。它应该实例化一个具体工厂类,具体取决于应用配置或当前环境。将这个工厂对象传递给所有构建产品的类。

  6. 扫描代码,找到所有直接调用产品构造子。用调用工厂对象上的相应创建方法替换它们。

七.优缺点

  1. 优点:

    • 你可以放心,工厂里买到的产品彼此兼容。

    • 你会避免具体产品和客户代码之间的紧密耦合。

    • 单一责任原则。你可以把产品创建代码提取到一个地方,让代码更容易支持。

    • 开闭原则。你可以在不破坏现有客户端代码的情况下引入新的产品变体。

  2. 缺点

    • 代码可能会变得比应有的更复杂,因为会随着模式引入许多新的接口和类。

八.与其他模式的关系

  • 许多设计从工厂方法开始(简单且通过子职业更可定制),随后逐步发展为抽象工厂、原型或建造者(更灵活但更复杂)。

  • 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;
}

执行结果

复制代码
===== 生产小米产品族 =====
我是【小米手机】,属于小米产品族
我是【小米路由器】,属于小米产品族
​
===== 生产华为产品族 =====
我是【华为手机】,属于华为产品族
我是【华为路由器】,属于华为产品族
相关推荐
weixin_465790913 天前
PLC做配方三轴螺丝机程序 配合流水线使用的三轴吸钉式自动锁螺丝机 (就是用流水线到位信号启动...
抽象工厂模式
Geoking.9 天前
【设计模式】抽象工厂模式(Abstract Factory)详解:一次创建“一整套产品”
设计模式·抽象工厂模式
西幻凌云11 天前
认识设计模式——工厂模式
c++·设计模式·简单工厂模式·抽象工厂模式·工厂模式
阿拉斯攀登14 天前
设计模式:工厂模式概要
java·设计模式·抽象工厂模式
阿闽ooo20 天前
抽象工厂模式实战:用C++打造家具生产系统(附UML图与完整代码)
c++·设计模式·抽象工厂模式·uml
明洞日记20 天前
【设计模式手册022】抽象工厂模式 - 创建产品家族
java·设计模式·抽象工厂模式
虫小宝21 天前
返利软件架构设计:多平台适配的抽象工厂模式实践
java·开发语言·抽象工厂模式
JavaBoy_XJ24 天前
创建型-抽象工厂模式
抽象工厂模式
SadSunset1 个月前
(15)抽象工厂模式(了解)
java·笔记·后端·spring·抽象工厂模式