C++设计模式——抽象工厂模式

文章目录

C++ 中的抽象工厂模式是一种创建型设计模式,它主要用于处理对象家族的创建,这些对象之间可能存在一定的关联关系或属于相同的产品族。抽象工厂模式的核心目标是提供一个接口,允许客户端通过此接口创建一系列相关或相互依赖的对象,而不必知道具体产生的对象的具体类。

抽象工厂模式的主要组成部分

  1. 抽象工厂(Abstract Factory):这是一个接口,声明了一组用于创建相关或依赖对象的方法,每个方法对应一种产品对象。

    cpp 复制代码
    class AbstractFactory {
    public:
      virtual ~AbstractFactory() {}
      virtual IProductA* createProductA() = 0; // 创建产品A的抽象方法
      virtual IProductB* createProductB() = 0; // 创建产品B的抽象方法
      // ... 可能还有其他产品方法
    };
  2. 具体工厂(Concrete Factory):这是抽象工厂接口的具体实现类,它负责创建一个产品族内的具体产品对象。

    cpp 复制代码
    class ConcreteFactory1 : public AbstractFactory {
    public:
      IProductA* createProductA() override { return new ConcreteProductA1(); }
      IProductB* createProductB() override { return new ConcreteProductB1(); }
    };
    
    class ConcreteFactory2 : public AbstractFactory {
    // ...
    };
  3. 产品接口(Product Interface):代表产品对象的抽象接口,定义了产品的公共方法。

    cpp 复制代码
    class IProductA {
    public:
      virtual ~IProductA() {}
      // 声明产品A的相关操作
    };
    
    class IProductB {
    public:
      virtual ~IProductB() {}
      // 声明产品B的相关操作
    };
  4. 具体产品(Concrete Product):实现了产品接口的具体产品类。

    cpp 复制代码
    class ConcreteProductA1 : public IProductA {
    // 实现产品A1的具体行为
    };
    
    class ConcreteProductB1 : public IProductB {
    // 实现产品B1的具体行为
    };
    
    // 同样会有 ConcreteProductA2, ConcreteProductB2 等...

使用抽象工厂模式的优势在于:

  • 隔离了具体的产品实现:客户端只需关心抽象工厂的接口,无需了解创建对象的具体细节。
  • 方便产品族的整体替换:如果想切换到同一产品族的不同实现,只需更改使用的具体工厂即可。
  • 确保产品一致性:通过抽象工厂创建的对象遵循一套一致的设计规则,适合那些必须一起工作的对象集合。

然而,抽象工厂模式也有其局限性,例如难以添加新的产品种类,因为它要求修改抽象工厂接口以及相应的具体工厂实现。此外,随着产品数量的增加,系统的复杂性也会提高。

抽象工厂模式的一个典型例子

在实际应用中,抽象工厂模式的一个典型例子是操作系统 GUI 库的创建。比如,我们有一个抽象工厂来创建按钮、文本框等各种 GUI 组件,而每个具体工厂(如 WindowsFactory 或 LinuxFactory)则负责创建相应操作系统下的具体 GUI 组件。

cpp 复制代码
// 抽象工厂接口
class GUIFactory {
public:
    virtual ~GUIFactory() {}
    virtual Button* createButton() const = 0;
    virtual TextBox* createTextBox() const = 0;
    // 其他组件的创建方法...
};

// 具体工厂
class WindowsFactory : public GUIFactory {
public:
    Button* createButton() const override { return new WindowsButton(); }
    TextBox* createTextBox() const override { return new WindowsTextBox(); }
    // ...
};

class LinuxFactory : public GUIFactory {
public:
    Button* createButton() const override { return new LinuxButton(); }
    TextBox* createTextBox() const override { return new LinuxTextBox(); }
    // ...
};

// 产品接口
class Button {
public:
    virtual ~Button() {}
    virtual void draw() const = 0;
    // ...
};

class TextBox {
public:
    virtual ~TextBox() {}
    virtual void draw() const = 0;
    // ...
};

// 具体产品
class WindowsButton : public Button {
public:
    void draw() const override { /*绘制Windows风格的按钮*/ }
    // ...
};

class WindowsTextBox : public TextBox {
public:
    void draw() const override { /*绘制Windows风格的文本框*/ }
    // ...
};

// Linux下对应的Button和TextBox实现...

在客户端代码中,我们可以根据需要选择合适的工厂来创建一整套风格一致的界面组件:

cpp 复制代码
int main() {
    GUIFactory* factory;
    if (isWindowsPlatform()) {
        factory = new WindowsFactory();
    } else if (isLinuxPlatform()) {
        factory = new LinuxFactory();
    }

    Button* myButton = factory->createButton();
    TextBox* myTextBox = factory->createTextBox();

    // 使用创建出来的组件
    myButton->draw();
    myTextBox->draw();

    delete myButton;
    delete myTextBox;
    delete factory;

    return 0;
}

这样,无论操作系统环境如何变化,客户端代码都可以保持不变,体现了开闭原则------对扩展开放,对修改关闭。同时,由同一家工厂创建出来的组件具有内在的一致性,可以很好地协同工作。

抽象工厂模式用于其他场景

此外,抽象工厂模式还常用于其他场景,例如:

  • 数据库访问:抽象工厂可以定义创建不同数据库连接、执行SQL命令等操作的方法,而具体工厂可以是MySQLFactory、OracleFactory等,分别用来创建各自数据库系统的连接对象和查询命令对象。
cpp 复制代码
// 抽象工厂
class DatabaseFactory {
public:
    virtual ~DatabaseFactory() {}
    virtual Connection* createConnection() const = 0;
    virtual Query* createQuery() const = 0;
};

// 具体工厂
class MySQLFactory : public DatabaseFactory {
public:
    Connection* createConnection() const override { return new MySQLConnection(); }
    Query* createQuery() const override { return new MySQLQuery(); }
};

class OracleFactory : public DatabaseFactory {
public:
    Connection* createConnection() const override { return new OracleConnection(); }
    Query* createQuery() const override { return new OracleQuery(); }
};

// 产品接口
class Connection {
public:
    virtual ~Connection() {}
    virtual bool connect(const std::string& host, int port, const std::string& user, const std::string& password) = 0;
    // 其他连接相关方法...
};

class Query {
public:
    virtual ~Query() {}
    virtual ResultSet* execute(const std::string& sql) = 0;
    // 其他查询相关方法...
};

// 具体产品类...

通过这种设计模式,软件架构得以解耦,使得各个部分能够独立变化和发展,同时确保了系统内部组件间的兼容性和一致性。在复杂的应用场景中,抽象工厂模式尤其有助于模块化设计和维护。

抽象工厂模式与其他设计模式结合使用

在更高级别的软件体系结构设计中,抽象工厂模式还可以与其他设计模式结合使用,以构建更为灵活和可扩展的解决方案。例如:

  • 与策略模式结合:抽象工厂可以返回一组实现了某种策略接口的对象,这样客户可以根据需求选择不同的策略组合。例如,在图形渲染引擎中,抽象工厂可以创建不同的渲染策略(如光照策略、纹理策略),然后将它们组合起来形成特定的效果。

  • 与工厂方法模式结合:抽象工厂中的某些方法可以进一步采用工厂方法模式,即在具体工厂内定义创建单个产品的工厂方法,使得产品创建逻辑更加灵活且易于扩展。

  • 与装饰器模式配合:当产品家族中存在需要逐步增强或修改的组件时,可以在获取基础组件后,通过装饰器模式为其添加额外的功能或属性。

  • 与服务定位器模式搭配:在大型系统中,抽象工厂可以与服务定位器模式相结合,通过服务定位器查找并注入所需的抽象工厂实例,以便在运行时决定具体使用哪种工厂。

总的来说,抽象工厂模式是一个强大而实用的设计模式,它不仅帮助我们组织和管理相关联的产品族,而且在很大程度上增强了代码的可复用性和可扩展性。但在实际应用时需要注意权衡其带来的灵活性与增加的复杂性,尤其是在产品家族变动频繁或者产品种类较少的情况下,直接使用简单工厂或工厂方法模式可能更为合适。

python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)

50个开发必备的Python经典脚本(11-20)

50个开发必备的Python经典脚本(21-30)

50个开发必备的Python经典脚本(31-40)

50个开发必备的Python经典脚本(41-50)


​最后我们放松一下眼睛

相关推荐
UestcXiye1 小时前
《TCP/IP网络编程》学习笔记 | Chapter 3:地址族与数据序列
c++·计算机网络·ip·tcp
霁月风2 小时前
设计模式——适配器模式
c++·适配器模式
jrrz08283 小时前
LeetCode 热题100(七)【链表】(1)
数据结构·c++·算法·leetcode·链表
咖啡里的茶i3 小时前
Vehicle友元Date多态Sedan和Truck
c++
WaaTong3 小时前
《重学Java设计模式》之 单例模式
java·单例模式·设计模式
海绵波波1073 小时前
Webserver(4.9)本地套接字的通信
c++
@小博的博客3 小时前
C++初阶学习第十弹——深入讲解vector的迭代器失效
数据结构·c++·学习
爱吃喵的鲤鱼4 小时前
linux进程的状态之环境变量
linux·运维·服务器·开发语言·c++
7年老菜鸡5 小时前
策略模式(C++)三分钟读懂
c++·qt·策略模式
Ni-Guvara5 小时前
函数对象笔记
c++·算法