抽象工厂模式
增加新的系列,工厂能够轻松扩展,而不需要大改生产线(原来的代码)。
efine _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<map>
#include<string>
#include<vector>
#include<memory>
using namespace std;
//按钮接口:抽象产品
class Button
{
public:virtual void display() = 0;
};
//Spring按钮:具体产品
class SpringButton :public Button
{
public:void display(){cout << "显示绿色按钮" << endl;}
};
//Summer按钮类:
class SummerButton :public Button
{
public:void display(){cout << "显示蓝色按钮" << endl;}
};//文本框接口:抽象产品
class TextField
{
public:virtual void display() = 0;
};
//Spring文本框:具体产品
class SpringTextField :public TextField
{
public:void display(){cout << "显示绿色边文本框" << endl;}
};
//Summer文本框:具体产品
class SummerTextField :public TextField
{
public:void display(){cout << "显示蓝色边文本框" << endl;}
};
//界面皮肤工厂接口:抽象工厂
class SkinFactory
{
public://virtual Button* createButton() = 0;virtual std::unique_ptr<Button> createButton() = 0;//virtual TextField* createTextFiled() = 0;virtual std::unique_ptr<TextField> createTextField() = 0;
};
//Spring皮肤工厂:具体工厂
class SpringSkinFactory :public SkinFactory
{
public:std::unique_ptr<Button> createButton(){return std::make_unique<SpringButton>();}std::unique_ptr<TextField> createTextField(){return std::make_unique<SpringTextField>();}
};
class SummerSkinFactory :public SkinFactory
{
public:std::unique_ptr<Button> createButton(){return std::make_unique<SummerButton>();}std::unique_ptr<TextField> createTextField(){return std::make_unique<SummerTextField>();}
};
int main()
{std::unique_ptr<SkinFactory> factory = nullptr;std::unique_ptr<Button> bt = nullptr;std::unique_ptr<TextField> tf = nullptr;factory = std::make_unique<SummerSkinFactory>();bt = factory->createButton();tf = factory->createTextField();bt->display();tf->display();return 0;
}
象工厂模式(Abstract Factory Pattern)主要解决了以下几类问题:
1. 产品族创建的复杂性问题
问题:当需要创建一组相互关联或依赖的产品对象时,直接实例化会导致客户端代码与具体类高度耦合
解决:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类
2. 系统可扩展性问题
问题:传统工厂方法在添加新产品族时需要修改大量代码
解决:通过抽象工厂接口,可以轻松添加新的产品族(符合开闭原则)
3. 产品一致性要求问题
问题:需要确保一组产品对象必须一起使用(如不同操作系统的UI控件不能混用)
解决:工厂内部保证创建的产品属于同一产品族,客户端无法创建不匹配的产品组合
4. 多平台/多环境适配问题
问题:同一套功能需要适配不同平台(如Windows/Mac的UI控件)
解决:每个平台实现自己的具体工厂,客户端代码与平台无关
5. 对象创建与使用的耦合问题
问题:客户端需要了解具体产品类的细节
解决:客户端只与抽象接口交互,完全解耦具体实现
设计原则体现:
依赖倒置原则:客户端依赖抽象而非具体类
开闭原则:扩展新产品族无需修改现有代码
单一职责原则:每个工厂只负责创建特定产品族
里氏替换原则:具体工厂可替换抽象工厂
耦合(Coupling)
耦合 指的是代码模块之间的依赖关系。它衡量一个模块(类、函数、组件)对另一个模块的了解程度。
耦合的类型
紧耦合(High Coupling)
模块之间高度依赖,修改一个模块可能影响多个其他模块。
缺点:代码难以维护、扩展困难、测试复杂。
例子:
class MySQLDatabase { public:void query() { /* MySQL 查询逻辑 */ } };class UserService { private:MySQLDatabase db; // 直接依赖 MySQLDatabase public:void getUser() { db.query(); } };
UserService
直接依赖MySQLDatabase
,如果要换成PostgreSQL
,必须修改UserService
。
松耦合(Low Coupling)
模块之间依赖接口或抽象,而不是具体实现。
优点:易于扩展、维护、测试。
例子:
class Database { public:virtual void query() = 0; };class MySQLDatabase : public Database { public:void query() override { /* MySQL 查询逻辑 */ } };class PostgreSQLDatabase : public Database { public:void query() override { /* PostgreSQL 查询逻辑 */ } };class UserService { private:Database* db; // 依赖抽象,而不是具体实现 public:UserService(Database* db) : db(db) {}void getUser() { db->query(); } };
UserService
只依赖Database
接口,可以轻松切换不同的数据库实现。
开闭原则(Open/Closed Principle, OCP)
开闭原则 是 SOLID 设计原则 之一,由 Bertrand Meyer 提出,核心思想:
"软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。"
含义
对扩展开放(Open for Extension)
允许在不修改现有代码的情况下,通过 继承、组合、接口实现 等方式扩展功能。
对修改关闭(Closed for Modification)
已有的核心代码(如接口、抽象类)不应被频繁修改,避免引入新 Bug。
如何实现开闭原则?
使用抽象(接口/基类),让具体实现可扩展。
依赖注入(Dependency Injection, DI),避免硬编码依赖。
策略模式、工厂模式 等设计模式帮助解耦。
例子
违反 OCP 的情况:
class PaymentProcessor {
public:void processPayment(string type) {if (type == "credit") {// 处理信用卡支付} else if (type == "paypal") {// 处理 PayPal 支付}// 如果要新增支付方式,必须修改这个类}
};
每次新增支付方式都要修改
processPayment
,违反 OCP。
符合 OCP 的情况:
class PaymentMethod {
public:virtual void pay() = 0;
};class CreditCardPayment : public PaymentMethod {
public:void pay() override { /* 信用卡支付逻辑 */ }
};class PayPalPayment : public PaymentMethod {
public:void pay() override { /* PayPal 支付逻辑 */ }
};class PaymentProcessor {
public:void processPayment(PaymentMethod* method) {method->pay(); // 依赖抽象,支持扩展}
};
新增支付方式只需继承
PaymentMethod
,无需修改PaymentProcessor
。
耦合 vs. 开闭原则的关系
概念 | 耦合 | 开闭原则 |
---|---|---|
目标 | 降低模块间的依赖 | 使代码易于扩展,避免修改已有代码 |
实现方式 | 依赖抽象(接口) | 依赖抽象(接口) |
关联 | 松耦合的代码更容易符合开闭原则 |
总结
耦合 衡量代码模块之间的依赖程度,松耦合 是良好设计的关键。
开闭原则 强调 扩展开放,修改关闭,避免频繁修改核心代码。
两者结合:通过 抽象、接口、设计模式 实现松耦合,使代码更易扩展和维护。