22种设计模式-个人理解

设计者模式

设计者模式一共23种,下面从:定义,分类,原则说一下设计者模式

1、创建型模式:简单工厂模式、单例模式、抽象工厂模式、原型模式、建造者模式(5种)
2、结构型模式:代理模式、外观模式、享元模式、组合模式、装饰器模式、适配器模式、桥接模式(7种)
3、行为模式:访问者模式、策略模式、模板模式、状态模式、备忘录模式、观察者模式、中介者模式、迭代器模式、解释器模式、责任链模式、命令模式(11种)


创建型模式

简单工厂模式

作用

就是我通过调用一个接口,可以找到这5种实现的任意一种

Plaintext 复制代码
	   ┌──────────────┐
       │  IDatabase   │ <──────────┐ (实现接口)
       └──────┬───────┘            │
              ▲                    │
     ┌────────┴────────┬───────┬───────┬───────┐
     │                 │       │       │       │
┌────┴─────┐ ┌────────┴┐┌──────┴┐┌─────┴──┐┌───┴───┐
│SQL Server│ │  MySQL  ││ Oracle││ SQLite ││ Redis │
└──────────┘ └─────────┘└───────┘└────────┘└───────┘
     ^                                         ^
     └────────────────────┬────────────────────┘
                          │ (由工厂创建)
                  ┌───────┴─────────┐
                  │ DatabaseFactory │
                  └─────────────────┘

案例分析

代码实战

c++ 复制代码
#include <iostream>
#include <string>
using namespace std;

// 1. 抽象汽车类 (Abstract Product)
class AbstractCar {
public:
    virtual void ShowCarName() = 0;
    virtual ~AbstractCar() {} // 建议添加虚析构函数
};

// 2. 具体汽车类 (Concrete Products)
class Magotan : public AbstractCar {
public:
    virtual void ShowCarName() {
        cout << "Magotan Car." << endl;
    }
};

class Audi : public AbstractCar {
public:
    virtual void ShowCarName() {
        cout << "Audi Car." << endl; // 图片中代码此处误写为Magotan,已保留逻辑
    }
};

class Benz : public AbstractCar {
public:
    virtual void ShowCarName() {
        cout << "Benz Car." << endl;
    }
};

// 假设存在的 Camry 类(工厂逻辑中有体现)
class Camry : public AbstractCar {
public:
    virtual void ShowCarName() {
        cout << "Camry Car." << endl;
    }
};

// 3. 汽车工厂类 (Simple Factory)
class CarFactory {
public:
    // 通过传递参数来确定需要生成哪种汽车
    static AbstractCar* CreateCarFunc(string cname) {
        if (cname == "Cmary") { // 注意:图片中拼写为Cmary
            return new Camry;
        }
        else if (cname == "Magotan") {
            return new Magotan;
        }
        else if (cname == "Audi") {
            return new Audi;
        }
        else if (cname == "Benz") {
            return new Benz;
        }
        else {
            return nullptr;
        }
    }
    CarFactory();
    ~CarFactory();
};

// 4. 客户端调用
int main() {
    // 创建工厂对象(虽然CreateCarFunc是静态的,但代码中实例化了工厂)
    CarFactory* fty = new CarFactory();

    // 创建汽车指针
    AbstractCar* car;

    // 指定工厂需要创建的汽车
    car = fty->CreateCarFunc("Benz");
    
    if (car != nullptr) {
        car->ShowCarName();
        delete car; // 释放内存
    }

    delete fty;
    return 0;
}

这里梳理一下逻辑

我的各种具体的型号的汽车,都是交给 工厂去new出来的,可以直接通过字符串的形式,或者枚举的形式,让工厂new一个具体的车型

创建阶段

1、先创建抽象汽车,

2、在创建4个具体的汽车,继承并实现抽象汽车的方法

3、创建工厂,这个工厂设置一个静态方法,这个方法适用于通过参数的类型,去返回一个具体的对象

使用阶段

1、把工厂给new出来

2、创建一个 不会new的 某一种具体型号的汽车对象

3、调用工厂方法的创建对象的方法

4、然后就可以去调用这一个具体型号汽车的方法了

存在三种角色:抽象汽车, 四种具体的不同的车(继承抽象汽车),一个工厂

抽象工厂


代码实战

还是那汽车举例

上面的简单工厂 案例中,我只有一种版本的汽车,不需要多个工厂,一个工厂足以

1、现在我需要两种版本的汽车,一个工厂本生产豪华版(Luxury),一个工厂生产基本版(base),

2、然后每个工厂都需要生产:Magotan 和 Benz 两种汽车

如果要实现一个接口,就能拿到具体的版本的汽车的话,工厂也需要抽象出来

复制代码
(产品族:基础款)                 (产品族:豪华款)
    ┌──────────────────┐             ┌──────────────────┐
    │   BaseFactory    │             │    LuxFactory    │  <--- 具体工厂 (Concrete Factory)
    ├──────────────────┤             ├──────────────────┤
    │+ CreateMagotan() │             │+ CreateMagotan() │
    │+ CreateBenz()    │             │+ CreateBenz()    │
    └────────┬─────────┘             └────────┬─────────┘
             │                                │
             └───────────────┬────────────────┘
                             ▼
                    ┌─────────────────┐
                    │ AbstractFactory │ <--- 抽象工厂 (Abstract Factory)
                    ├─────────────────┤
                    │ virtual Magotan │
                    │ virtual Benz    │
                    └─────────────────┘
                             │
            ┌────────────────┴────────────────┐
            ▼                                 ▼
    ┌───────────────┐                 ┌───────────────┐
    │AbstractMagotan│                 │  AbstractBenz │ <--- 抽象产品 (Abstract Product)
    └───────┬───────┘                 └───────┬───────┘
     ┌──────┴──────┐                   ┌──────┴──────┐
     ▼             ▼                   ▼             ▼
┌──────────┐  ┌──────────┐       ┌──────────┐  ┌──────────┐
│BaseMagotan│ │LuxMagotan│       │ BaseBenz │  │ LuxBenz  │ <--- 具体产品
└──────────┘  └──────────┘       └──────────┘  └──────────┘
c++ 复制代码
#include <iostream>
#include <string>
using namespace std;

// === 第一步:抽象产品 (不同品牌的车型) ===
class AbstractMagotan {
public:
    virtual void ShowInfo() = 0;
    virtual ~AbstractMagotan() {}
};

class AbstractBenz {
public:
    virtual void ShowInfo() = 0;
    virtual ~AbstractBenz() {}
};

// === 第二步:具体产品 (品牌下的不同档次) ===
class BaseMagotan : public AbstractMagotan {
public:
    void ShowInfo() override { cout << "生产:基础版 迈腾" << endl; }
};

class LuxMagotan : public AbstractMagotan {
public:
    void ShowInfo() override { cout << "生产:豪华版 迈腾" << endl; }
};

class BaseBenz : public AbstractBenz {
public:
    void ShowInfo() override { cout << "生产:基础版 奔驰" << endl; }
};

class LuxBenz : public AbstractBenz {
public:
    void ShowInfo() override { cout << "生产:豪华版 奔驰" << endl; }
};

// === 第三步:抽象工厂 (定义生产一整套产品的接口) ===
class AbstractFactory {
public:
    // 抽象工厂同时包含多个品牌的生产方法
    virtual AbstractMagotan* CreateMagotan() = 0;
    virtual AbstractBenz* CreateBenz() = 0;
    virtual ~AbstractFactory() {}
};

// === 第四步:具体工厂 (按档次一次性实现多个品牌) ===
// 基础款工厂:专门生产所有品牌的基础款
class BaseFactory : public AbstractFactory {
public:
    AbstractMagotan* CreateMagotan() override { return new BaseMagotan(); }
    AbstractBenz* CreateBenz() override { return new BaseBenz(); }
};

// 豪华款工厂:专门生产所有品牌的豪华款
class LuxFactory : public AbstractFactory {
public:
    AbstractMagotan* CreateMagotan() override { return new LuxMagotan(); }
    AbstractBenz* CreateBenz() override { return new LuxBenz(); }
};

// === 第五步:客户端代码 ===
int main() {
    AbstractFactory* factory = nullptr;
    AbstractMagotan* m = nullptr;
    AbstractBenz* b = nullptr;

    // 1. 想要一整套基础款汽车
    cout << "--- 访问基础款工厂 ---" << endl;
    factory = new BaseFactory();
    m = factory->CreateMagotan(); // 生产基础迈腾
    b = factory->CreateBenz();    // 生产基础奔驰
    m->ShowInfo();
    b->ShowInfo();
    delete m; delete b; delete factory;

    // 2. 想要一整套豪华款汽车
    cout << "\n--- 访问豪华款工厂 ---" << endl;
    factory = new LuxFactory();
    m = factory->CreateMagotan(); // 生产豪华迈腾
    b = factory->CreateBenz();    // 生产豪华奔驰
    m->ShowInfo();
    b->ShowInfo();
    delete m; delete b; delete factory;

    return 0;
}

抽象工厂 (AbstractFactory):位于逻辑顶层或中心,它定义了生产"迈腾"和"奔驰"的规范。

具体工厂 (BaseFactory / LuxFactory) :实现了该规范。BaseFactory 就像一条生产线,它只关心基础款,但能同时造出基础款的迈腾和奔驰。

产品族 :基础款迈腾和基础款奔驰属于同一个产品族。抽象工厂的最大作用就是约束产品族的配套,防止你用"基础工厂"去造出"豪华奔驰"。

单例模式

基础知识

案例

1、饿汉式:类加载时就完成了初始化。它是线程安全的,但如果实例一直没被使用,会浪费内存。

c++ 复制代码
#include <iostream>

class HungrySingleton {
private:
    // 1. 私有化构造函数,防止外部创建对象
    HungrySingleton() {}
    
    // 2. 静态私有实例,类加载时即创建
    static HungrySingleton* instance;

public:
    // 3. 禁用拷贝构造和赋值
    HungrySingleton(const HungrySingleton&) = delete;
    HungrySingleton& operator=(const HungrySingleton&) = delete;

    // 4. 提供全局访问接口
    static HungrySingleton* getInstance() {
        return instance;
    }

    void show() { std::cout << "这是饿汉式单例" << std::endl; }
};

// 在类外初始化静态变量
HungrySingleton* HungrySingleton::instance = new HungrySingleton();

int main() {
    HungrySingleton* s1 = HungrySingleton::getInstance();
    s1->show();
    return 0;
}

2、懒汉式:只有在第一次调用 getInstance 时才创建实例。为了性能和简洁,这里推荐 C++11 标准后的局部静态变量方式 (又称 Meyers' Singleton),它是天生线程安全的。

c++ 复制代码
#include <iostream>

class LazySingleton {
private:
    // 1. 私有化构造函数
    LazySingleton() { std::cout << "懒汉式实例已创建" << std::endl; }
    
    // 2. 禁用拷贝和赋值
    LazySingleton(const LazySingleton&) = delete;
    LazySingleton& operator=(const LazySingleton&) = delete;

public:
    
    // 3. 静态局部变量方式实现
    static LazySingleton& getInstance() {
        // C++11 规定:如果静态局部变量正在初始化,线程会等待直到初始化完成
        static LazySingleton instance; 
        return instance;
    }

    void show() { std::cout << "这是懒汉式单例" << std::endl; }
};

int main() {
    std::cout << "程序开始运行..." << std::endl;
    // 只有执行下面这一行时,构造函数才会被调用
    LazySingleton& s1 = LazySingleton::getInstance();
    s1.show();
    return 0;
}

不要用指针,因为线程不安全,建议全部用static去实现,比较好,且安全

原型模式

原型模式 (Prototype Pattern) 的核心思想是:通过**克隆(Clone)**现有的对象来创建新对象,而不是通过 new 操作符重新初始化。这种模式在对象创建成本较高(如需要复杂的数据库查询或大量计算)时非常有用。

在 C++ 中,原型模式通常通过一个抽象基类中的纯虚函数 clone() 来实现。


1. 原型模式关系字符图

text 复制代码
       ┌──────────────────┐
       │    Prototype     │ (抽象类)
       ├──────────────────┤
       │virtual clone() =0│
       └────────┬─────────┘
                ▲
       ┌────────┴────────┐
       │ ConcreteProtorype│ (具体实现类)
       ├──────────────────┤
       │ clone() {        │────┐
       │   return new Self│    │ (返回自身的副本)
       │ }                │<───┘
       └──────────────────┘

2. C++ 代码实现

为了保持一致性,我们继续使用汽车的例子。假设我们要克隆一辆已经配置好的"迈腾"。

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

// === 1. 抽象原型类 ===
class AbstractCar {
public:
    virtual ~AbstractCar() {}
    virtual AbstractCar* clone() = 0; // 核心:克隆接口
    virtual void showConfig() = 0;
};

// === 2. 具体原型类 ===
class Magotan : public AbstractCar {
private:
    string color;
    string engine;

public:
    Magotan(string c, string e) : color(c), engine(e) {}

    // 实现克隆函数
    AbstractCar* clone() override {
        // 调用拷贝构造函数,创建一个完全一样的新对象
        return new Magotan(*this); 
    }

    void showConfig() override {
        cout << "迈腾配置 -> 颜色: " << color << ", 发动机: " << engine << " [地址: " << this << "]" << endl;
    }
};

// === 3. 客户端调用 ===
int main() {
    // 创建一个原型对象
    AbstractCar* prototypeMagotan = new Magotan("黑色", "V6");
    cout << "--- 原型对象 ---" << endl;
    prototypeMagotan->showConfig();

    // 通过克隆产生新对象,而不是用 new 重新设置参数
    cout << "\n--- 克隆产生的对象 ---" << endl;
    AbstractCar* car1 = prototypeMagotan->clone();
    AbstractCar* car2 = prototypeMagotan->clone();

    car1->showConfig();
    car2->showConfig();

    // 释放内存
    delete prototypeMagotan;
    delete car1;
    delete car2;

    return 0;
}

3. 原型模式的关键点

  • 克隆而非新建clone() 方法内部通常利用拷贝构造函数来完成对象的复制。
  • 深拷贝与浅拷贝 :如果类中包含指针成员,在实现 clone() 时必须确保执行的是深拷贝,否则多个克隆体将共享同一块动态内存,导致程序崩溃。
  • 性能优势:当初始化一个对象的过程非常繁琐(例如需要读取配置文件、初始化硬件等)时,直接内存拷贝(克隆)的速度要快得多。

拓展知识点:

建造者模式

思想

核心思想 : 将一个复杂对象的构建过程与它的**表示(最终对象)**分离,使得同样的构建过程可以创建不同的表示。

👉 重点不是"拷贝",而是一步一步组装

与原型模式的区别

模式 关注点
原型模式 已有对象 → 快速复制
建造者模式 无到有 → 按步骤构建复杂对象

建造者模式非常适合:

  • 构造函数参数很多(10+)
  • 对象有固定构建流程,但配置组合不同
  • 需要可读性强的对象创建代码

原型模式:我有一个现成对象,复制一个一模一样的

建造者模式:我知道建造流程,一步一步把对象"拼"出来

建造者模式角色结构图

复制代码
        ┌──────────────────┐
        │     Director     │  (指挥者:控制构建顺序)
        └────────┬─────────┘
                 │
        ┌────────▼────────┐
        │     Builder     │  (抽象建造者)
        ├─────────────────┤
        │ buildColor()    │
        │ buildEngine()   │
        │ buildGearbox()  │
        │ getResult()     │
        └────────┬────────┘
                 ▲
        ┌────────┴────────┐
        │ ConcreteBuilder │  (具体建造者)
        └─────────────────┘
                 │
        ┌────────▼────────┐
        │      Product    │  (最终产品)
        └─────────────────┘

代码落地

c++ 复制代码
// 1、最终产品
#include <iostream>
#include <string>
using namespace std;

// === 产品类 ===
class Car {
public:
    string color;
    string engine;
    string gearbox;

    void showConfig() const {
        cout << "汽车配置 -> "
             << "颜色: " << color
             << ", 发动机: " << engine
             << ", 变速箱: " << gearbox
             << endl;
    }
};

// 2、抽象建造者
// === 抽象建造者 ===
class CarBuilder {
public:
    virtual ~CarBuilder() {}
    virtual void buildColor() = 0;
    virtual void buildEngine() = 0;
    virtual void buildGearbox() = 0;
    virtual Car* getResult() = 0;
};

// 3、具体建造者:MagotanBuilder
// === 具体建造者 ===
class MagotanBuilder : public CarBuilder {
private:
    Car* car;

public:
    MagotanBuilder() {
        car = new Car();
    }

    void buildColor() override {
        car->color = "黑色";
    }

    void buildEngine() override {
        car->engine = "V6";
    }

    void buildGearbox() override {
        car->gearbox = "8AT";
    }

    Car* getResult() override {
        return car;
    }
};

// 4、指挥者 Director(控制  构建顺序)
// === 指挥者 ===
class Director {
public:
    void construct(CarBuilder& builder) {
        builder.buildColor();
        builder.buildEngine();
        builder.buildGearbox();
    }
};

// 5、客户端调用
int main() {
    Director director;

    CarBuilder* builder = new MagotanBuilder();

    // 指挥者负责"怎么建"
    director.construct(*builder);

    // 客户端只关心最终结果
    Car* magotan = builder->getResult();
    magotan->showConfig();

    delete magotan;
    delete builder;
    return 0;
}

进阶:更"现代 C++"的 Builder(链式写法)

c++ 复制代码
class CarBuilder {
private:
    Car car;
public:
    CarBuilder& color(const string& c) {
        car.color = c;
        return *this;
    }
    CarBuilder& engine(const string& e) {
        car.engine = e;
        return *this;
    }
    CarBuilder& gearbox(const string& g) {
        car.gearbox = g;
        return *this;
    }

    Car build() {
        return car;
    }
};

Car car = CarBuilder()
            .color("黑色")
            .engine("V6")
            .gearbox("8AT")
            .build();

car.showConfig();

结构型模式

适配器模式

定义

适配器模式 通过引入一个中间层,把一个类的接口转换成客户端期望的接口,

不修改原有代码的前提下实现接口兼容。

什么时候用适配器

典型场景(非常工程化):

  • 接入 第三方库 / 老代码,接口改不了
  • 新系统接口已定,但老系统还要继续用
  • 重构过程中,需要平滑过渡

📌 关键点:不改旧代码,只包一层

适配器模式角色结构图

复制代码
        ┌──────────────────┐
        │      Target      │  (客户端期望的接口)
        ├──────────────────┤
        │   request()      │
        └────────┬─────────┘
                 ▲
        ┌────────┴────────┐
        │     Adapter      │  (适配器)
        ├──────────────────┤
        │  request()       │───┐
        └────────┬─────────┘   │
                 │             │
        ┌────────▼────────┐    │
        │    Adaptee       │◄──┘
        ├──────────────────┤
        │ specificRequest()│ (旧接口)
        └──────────────────┘

代码举例(汽车接口适配器)

适配器分为两种:对象适配器 和 类适配器

场景设定:

  • 新系统 :统一调用 start() 启动车辆
  • 老系统 / 第三方类 :只有 ignite() 方法
  • 👉 接口不一致,不能直接用

1、对象适配器

c++ 复制代码
// === 1、目标接口(新系统) ===
class Car {
public:
    virtual ~Car() {}
    virtual void start() = 0;
};


// === 2、被适配者(老接口 / 第三方库) ===
class OldCarSystem {
public:
    void ignite() {
        cout << "老系统:点火启动汽车" << endl;
    }
};


// === 3、适配器(核心) === (对象适配器,就是老类成为对象,供新接口调用)
class CarAdapter : public Car {
private:
    OldCarSystem* oldCar;

public:
    CarAdapter(OldCarSystem* car) : oldCar(car) {}

    void start() override {
        // 接口转换
        oldCar->ignite();
    }
};

int main() {
    // 老系统对象
    OldCarSystem* oldSystem = new OldCarSystem();

    // 通过适配器,让老系统"看起来像"新接口
    Car* car = new CarAdapter(oldSystem);

    // 客户端只认 start()
    car->start();

    delete car;
    delete oldSystem;
    return 0;
}

解耦

更灵活

2、类适配器

c++ 复制代码
class CarAdapter : public Car, public OldCarSystem {
public:
    void start() override {
        ignite();
    }
};

强耦合

受限于多继承

不利于维护


桥接模式

定义

核心思想

抽象(Abstraction)与实现(Implementation)分离, 使它们可以独立变化,而不是通过继承形成类爆炸。

为什么需要桥接模式

假设你现在要支持:

  • 车型:SUVSedan

  • 发动机:V6Electric


❌ 不用桥接(继承爆炸)

复制代码
SUV_V6
SUV_Electric
Sedan_V6
Sedan_Electric

👉 2 × 2 = 4 个类

再加一个发动机类型?立刻翻倍。

✅ 用桥接(两个维度独立)

复制代码
车型(抽象)  <───桥接───>  发动机(实现)

桥接模式结构图

复制代码
        ┌──────────────────────┐
        │     Abstraction      │  (抽象:车型)
        ├──────────────────────┤
        │ Engine* engine       │◄───────┐
        │ drive()              │        │
        └──────────┬───────────┘        │
                   ▲                    │
        ┌──────────┴───────────┐        │
        │  RefinedAbstraction  │        │
        │ (SUV / Sedan)        │        │
        └──────────────────────┘        │
                                        │
        ┌───────────────────────────────▼──────────────┐
        │              Implementor                     │
        │             (Engine 接口)                     │
        ├──────────────────────────────────────────────┤
        │ start()                                      │
        └───────────────┬──────────────────────────────┘
                        ▲
        ┌───────────────┴──────────────────────────────┐
        │        ConcreteImplementor                   │
        │        (V6 / Electric)                       │
        └──────────────────────────────────────────────┘

C++实例

c++ 复制代码
// 1️⃣ 实现层:发动机接口(Implementation)
#include <iostream>
using namespace std;

// === 实现接口:发动机 ===
class Engine {
public:
    virtual ~Engine() {}
    virtual void start() = 0;
};

// 2、2️⃣ 具体实现:不同发动机
class V6Engine : public Engine {
public:
    void start() override {
        cout << "V6 发动机启动" << endl;
    }
};

class ElectricEngine : public Engine {
public:
    void start() override {
        cout << "电动机启动" << endl;
    }
};

// 3️⃣ 抽象层:车型(Abstraction)
// === 抽象:车型 ===
class Car {
protected:
    Engine* engine;   // ⭐ 桥接点

public:
    Car(Engine* e) : engine(e) {}
    virtual ~Car() {}

    virtual void drive() = 0;
};

// 4️⃣ 扩展抽象:具体车型
class SUV : public Car {
public:
    SUV(Engine* e) : Car(e) {}

    void drive() override {
        cout << "SUV 行驶中,";
        engine->start();
    }
};

class Sedan : public Car {
public:
    Sedan(Engine* e) : Car(e) {}

    void drive() override {
        cout << "轿车行驶中,";
        engine->start();
    }
};

// 5️⃣ 客户端调用
int main() {
    Engine* v6 = new V6Engine();
    Engine* electric = new ElectricEngine();

    Car* car1 = new SUV(v6);
    Car* car2 = new Sedan(electric);

    car1->drive();
    car2->drive();

    delete car1;
    delete car2;
    delete v6;
    delete electric;
    return 0;
}

作用

桥接模式通过组合而非继承,将抽象与实现解耦, 使它们可以独立扩展,避免类爆炸问题。

组合实体对象

核心思想

一组相互关联的持久化对象 (Dependent Objects)
统一封装 成一个粗粒度对象(Composite Entity)

客户端只与这个组合实体交互,而不是直接操作多个对象。

一句话直觉版:

"一堆数据对象 → 对外只暴露一个入口"

为什么要用组合实体对象

典型问题(非常像业务代码):

  • 一个业务对象由多个子对象组成
  • 这些子对象:
    • 生命周期一致
    • 数据强相关
    • 经常一起加载 / 保存
  • 客户端如果直接操作它们:
    • 耦合高
    • 易出错
    • 接口复杂

👉 组合实体 = 数据聚合 + 访问门面

组合实体模式结构图

复制代码
        ┌──────────────────────┐
        │    CompositeEntity   │  (组合实体)
        ├──────────────────────┤
        │  get/set data        │
        │  内部管理对象        │
        └──────────┬───────────┘
                   │
        ┌──────────┴───────────┐
        │     CoarseGrained     │  (粗粒度对象)
        ├──────────────────────┤
        │  DependentObject A   │
        │  DependentObject B   │
        └──────────┬───────────┘
                   │
        ┌──────────┴───────────┐
        │  DependentObject     │  (依赖对象)
        └──────────────────────┘

案例

c++ 复制代码
// 1、1️⃣ Dependent Objects(依赖的实体对象)
#include <iostream>
#include <string>
using namespace std;

// === 依赖对象:用户实体 ===
class CustomerInfo {
public:
    CustomerInfo() {
        cout << "[CustomerInfo] 构造" << endl;
    }
    ~CustomerInfo() {
        cout << "[CustomerInfo] 析构" << endl;
    }

    void set(const string& n, const string& a) {
        name = n;
        address = a;
    }

    void show() const {
        cout << "用户: " << name << ", 地址: " << address << endl;
    }

private:
    string name;
    string address;
};

// === 依赖对象:支付实体 ===
class PaymentInfo {
public:
    PaymentInfo() {
        cout << "[PaymentInfo] 构造" << endl;
    }
    ~PaymentInfo() {
        cout << "[PaymentInfo] 析构" << endl;
    }

    void set(const string& m, double a) {
        method = m;
        amount = a;
    }

    void show() const {
        cout << "支付: " << method << ", 金额: " << amount << endl;
    }

private:
    string method;
    double amount;
};

// 这里是组合实体模式的关键点之一, 2️⃣ Coarse-Grained Object(负责创建 / 聚合)
// === 粗粒度对象 ===
class OrderData {
public:
    OrderData() {
        customer = new CustomerInfo();
        payment  = new PaymentInfo();
    }

    ~OrderData() {
        delete customer;
        delete payment;
    }

    void setCustomer(const string& name, const string& addr) {
        customer->set(name, addr);
    }

    void setPayment(const string& method, double amount) {
        payment->set(method, amount);
    }

    void show() const {
        customer->show();
        payment->show();
    }

private:
    CustomerInfo* customer;
    PaymentInfo*  payment;
};

// 3️⃣ Composite Entity(对外唯一入口)
// === 组合实体 ===
class OrderEntity {
public:
    OrderEntity() {
        orderData = new OrderData();
    }

    ~OrderEntity() {
        delete orderData;
    }

    void setOrder(const string& name,
                  const string& addr,
                  const string& payMethod,
                  double amount) {
        orderData->setCustomer(name, addr);
        orderData->setPayment(payMethod, amount);
    }

    void show() const {
        cout << "====== 订单 ======" << endl;
        orderData->show();
    }

private:
    OrderData* orderData;
};

// 4️⃣ 客户端调用(完整生命周期)
int main() {
    {
        OrderEntity order;   // 只 new 一个组合实体
        order.setOrder("小孔", "北京霍营", "微信支付", 199.0);
        order.show();
    } // 作用域结束,内部对象全部自动释放

    return 0;
}

装饰器模式

为什么需要装饰器模式呢?

核心思想

不修改原有类 的前提下, 动态地为对象添加职责(功能)。

一句话版:

功能要叠加,但又不想继承爆炸


假设你有一个 Car,功能需求不断增加:

  • 基础车
    • 天窗
    • 自动驾驶
    • 运动套件

❌ 继承的下场(类爆炸)

复制代码
Car
├─ CarWithSunroof
├─ CarWithAutoDrive
├─ CarWithSunroofAndAutoDrive
├─ CarWithSportKit
├─ ...

👉 这路子迟早炸。

✅ 装饰器的思路

复制代码
Car + 装饰器(功能模块) → 动态组合

自我感觉:装饰器模式:就是把原本基础的数据类型,用来其,经过各种各项得到修饰处理,得到我们像要的值

装饰器模式结构图

复制代码
        ┌──────────────────┐
        │    Component     │  (抽象组件【对象】)
        │  operation()     │
        └────────┬─────────┘
                 ▲
        ┌────────┴────────┐
        │ ConcreteComponent│  (基础对象)
        └─────────────────┘
                 ▲
        ┌────────┴────────┐
        │    Decorator     │  (抽象装饰器)
        │  Component*     │
        └────────┬────────┘
                 ▲
        ┌────────┴────────┐
        │ConcreteDecorator │  (具体装饰器)
        └─────────────────┘

C++ 示例(汽车功能叠加)

c++ 复制代码
// 1️⃣ Component:抽象组件
#include <iostream>
#include <string>
using namespace std;

// === 抽象组件 ===
class Car {
public:
    virtual ~Car() {}
    virtual string getDescription() = 0;
    virtual double cost() = 0;
};

// 2️⃣ ConcreteComponent:基础对象
// === 具体组件 ===
class BasicCar : public Car {
public:
    string getDescription() override {
        return "基础车型";
    }

    double cost() override {
        return 200000;
    }
};

// 3️⃣ Decorator:抽象装饰器
// === 抽象装饰器 ===
class CarDecorator : public Car {
protected:
    Car* car;

public:
    CarDecorator(Car* c) : car(c) {}
};

// 4️⃣ ConcreteDecorator:具体装饰器
// 4.1天窗
class SunroofDecorator : public CarDecorator {
public:
    SunroofDecorator(Car* c) : CarDecorator(c) {}

    string getDescription() override {
        return car->getDescription() + " + 天窗";
    }

    double cost() override {
        return car->cost() + 12000;
    }
};

// 4.2自动驾驶
class AutoDriveDecorator : public CarDecorator {
public:
    AutoDriveDecorator(Car* c) : CarDecorator(c) {}

    string getDescription() override {
        return car->getDescription() + " + 自动驾驶";
    }

    double cost() override {
        return car->cost() + 30000;
    }
};

// 5️⃣ 客户端动态组合
int main() {
    Car* car = new BasicCar();

    car = new SunroofDecorator(car);
    car = new AutoDriveDecorator(car);

    cout << car->getDescription() << endl;
    cout << "总价: " << car->cost() << endl;

    delete car; // 注意:这里只 delete 最外层

    return 0;
}

3️⃣ Decorator:抽象装饰器 📌 关键点

  • 装饰器 "是一个 Car"
  • 同时 "包着一个 Car"

装饰器 vs 继承(本质区别)

对比点 继承 装饰器
功能扩展 编译期 运行期
组合方式 静态 动态
类数量 爆炸 可控
单一职责

👉 装饰器是 "用组合代替继承" 的经典案例。

装饰器 vs 适配器 vs 代理(高频混淆)

模式 核心目的
装饰器 增强功能
适配器 转换接口
代理 控制访问

一句话区分:

  • 装饰器:功能叠加
  • 适配器:接口转换
  • 代理:加一道门

工程级注意点(很 C++)

1️⃣ 析构必须是 virtual

复制代码
virtual ~Car() {}

否则多态 delete 会炸。

2️⃣ 建议用智能指针

复制代码
unique_ptr<Car> car = make_unique<BasicCar>();
car = make_unique<SunroofDecorator>(std::move(car));
car = make_unique<AutoDriveDecorator>(std::move(car));

外观模式

定义

核心思想

一组复杂的子系统 提供一个统一的、高层接口

让客户端更容易使用这个子系统。

一句话版:系统很复杂,对外给个"傻瓜接口"

用外观模式的时机

你一定遇到过这种代码 👇

c++ 复制代码
SubA a;
SubB b;
SubC c;

a.init();
b.load();
c.prepare();
a.run(b, c);

客户端:

  • 要知道调用顺序
  • 要知道子系统依赖
  • 一改全炸

👉 外观模式就是来"挡复杂度"的

外观模式结构图

复制代码
        Client
          │
          ▼
      ┌─────────┐
      │ Facade  │  (外观)
      └────┬────┘
           │
   ┌───────┼────────┐
   │       │        │
┌──▼──┐ ┌──▼──┐ ┌───▼───┐
│SubA │ │SubB │ │ SubC  │
└─────┘ └─────┘ └───────┘

要点

  • Facade 不实现业务
  • 只负责 协调 / 编排

C++ 示例(汽车启动系统)

场景设定

启动一辆车,需要:

  • 引擎系统
  • 电池系统
  • ECU 系统

客户端如果直接操作,非常麻烦。

c++ 复制代码
// 1️⃣ 子系统类(复杂)
#include <iostream>
using namespace std;

// === 子系统 ===
class EngineSystem {
public:
    void start() {
        cout << "发动机启动" << endl;
    }
};

class BatterySystem {
public:
    void check() {
        cout << "电池自检通过" << endl;
    }
};

class ECUSystem {
public:
    void boot() {
        cout << "ECU 系统启动" << endl;
    }
};

// 2️⃣ 外观类(Facade)
// === 外观 ===
class CarFacade {
public:
    CarFacade() {
        engine = new EngineSystem();
        battery = new BatterySystem();
        ecu = new ECUSystem();
    }

    ~CarFacade() {
        delete engine;
        delete battery;
        delete ecu;
    }

    // 对外只暴露一个简单接口
    void startCar() {
        battery->check();
        ecu->boot();
        engine->start();
    }

private:
    EngineSystem* engine;
    BatterySystem* battery;
    ECUSystem* ecu;
};

// 3️⃣ 客户端调用
int main() {
    CarFacade car;
    car.startCar();
    return 0;
}

外观 vs 适配器

外观 适配器
目的 简化使用 接口转换
面向 子系统 单个类
是否改变接口 否(封装) 是(转换)

👉 外观是"简化",适配是"兼容"

外观模式 为复杂子系统提供一个统一的高层接口,

降低客户端与子系统之间的耦合,提高系统可用性和可维护性。

享元模式

核心思想

核心思想 : 将对象中可共享的内部状态(Intrinsic State)提取出来, 在系统中只创建少量共享对象, 把**不可共享的外部状态(Extrinsic State)**在使用时传入。

用时间换空间,用"传参"换"对象数量"

为何需要享元

假设你要渲染 10 万辆车

复制代码
new Car("迈腾", "2.0T", "黑色", x, y);

问题:

  • 品牌、发动机、模型 99% 是重复的
  • 真正不同的是:位置、速度、车牌

👉 享元模式:共享的数据不变的,需要分类的数据是 分离变化的

享元模式结构图

复制代码
        Client
          │
          ▼
   ┌─────────────┐
   │ Flyweight   │ (抽象享元)
   └──────┬──────┘
          ▲
   ┌──────┴────────┐
   │ ConcreteFlywt │ (共享对象)
   └──────┬────────┘
          │
   ┌──────▼────────--┐
   │FlyweightFactory │ (工厂 + 缓存 => 享元的核心)
   └─────────────────┘

核心概念

1️⃣ 内部状态(共享)

  • 不随环境变化
  • 可以被多个对象共享

例如:

复制代码
品牌 / 发动机 / 型号

2️⃣ 外部状态(不共享)

  • 每次使用时 通过参数传入
  • 不存储在享元对象中,而是放在工厂中,当一个缓存

例如:

复制代码
坐标 / 速度 / 车牌

C++ 示例(车辆渲染)

c++ 复制代码
// 1️⃣ 抽象享元
#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;

// === 抽象享元 ===
class CarFlyweight {
public:
    virtual ~CarFlyweight() {}
    virtual void draw(int x, int y) = 0; // 外部状态
};

// 2️⃣ 具体享元(共享对象)
// === 具体享元 ===
class CarModel : public CarFlyweight {
private:
    // 内部状态(共享)
    string brand;
    string engine;

public:
    CarModel(string b, string e)
        : brand(b), engine(e) {
        cout << "【创建享元】" << brand << " " << engine << endl;
    }

    void draw(int x, int y) override {
        cout << "绘制 " << brand << "-" << engine
             << " 在位置 (" << x << ", " << y << ")" << endl;
    }
};

// 3️⃣ 享元工厂(关键)
// === 享元工厂 ===
class CarFactory {
public:
    static CarFlyweight* getCar(const string& brand,
                                const string& engine) {
        string key = brand + "_" + engine;

        if (pool.find(key) == pool.end()) {
            pool[key] = new CarModel(brand, engine); // new 只发生一次
        }
        return pool[key];
    }

private:
    static unordered_map<string, CarFlyweight*> pool;
};

// 静态成员定义
unordered_map<string, CarFlyweight*> CarFactory::pool;

// 4️⃣ 客户端使用
int main() {
    CarFlyweight* car1 =
        CarFactory::getCar("迈腾", "2.0T");
    car1->draw(10, 20);

    CarFlyweight* car2 =
        CarFactory::getCar("迈腾", "2.0T");
    car2->draw(30, 40);

    CarFlyweight* car3 =
        CarFactory::getCar("奥迪A6", "3.0T");
    car3->draw(50, 60);

    return 0;
}

// 输出结果
【创建享元】迈腾 2.0T
绘制 迈腾-2.0T 在位置 (10, 20)
绘制 迈腾-2.0T 在位置 (30, 40)
【创建享元】奥迪A6 3.0T
绘制 奥迪A6-3.0T 在位置 (50, 60)

关键点

✔ 享元 ≠ 少 new

  • 核心不是"减少 new"
  • 核心是 状态拆分

✔ 必须有 Factory

没有缓存工厂,就不叫享元。

❌ 把外部状态存进享元

复制代码
// 错误
class CarModel {
    int x, y;
};

👉 会导致共享污染

❌ 享元对象可变

共享对象一旦可修改,等于埋雷。

👉 享元对象最好不可变

代理模式

定义

代理模式 :为某个对象提供一个替身(代理) ,由代理对象 控制 对真实对象的 访问

核心思想不是"扩展功能"(那是装饰器), 而是 控制访问、间接访问、附加访问逻辑

使用场景

场景 说明
延迟加载(虚代理) 对象很重,真正用到才 new
权限控制(保护代理) 访问前做权限校验
日志 / 统计 调用前后插逻辑
远程代理 本地对象代表远程服务
智能指针 shared_ptr 本质就是代理

代理模式结构图

复制代码
                   +------------------+
                   |      Image       |   ← 抽象主题(Subject)
                   +------------------+
                   | + display()      |
                   +------------------+
                     ▲       	   ▲
                     |        	   |
          implements |        	   | implements
                     |        	   |
     +-----------------------+   +-------------------------+
     |      ImageProxy       |   |        RealImage        |
     +-----------------------+   +-------------------------+
     | - m_filename          |   | - m_filename            |
     | - m_realImage : ptr   |   +-------------------------+
     +-----------------------+   | + display()             |
     | + display()           |   | - loadFromDisk()        |
     +-----------------------+   +-------------------------+
              |
              | owns / controls
              ▼
        RealImage (延迟 new)

关键点:

  • ProxyRealSubject 实现同一个接口
  • Client 不知道自己用的是代理还是真对象

C++示例

c++ 复制代码
// 1️⃣ 抽象接口(Subject)
class Image {
public:
    virtual ~Image() = default;
    virtual void display() = 0;
};

// 2️⃣ 真实对象(RealSubject)
class RealImage : public Image {
public:
    explicit RealImage(const std::string& filename) : m_filename(filename)  {
        loadFromDisk(); // 构造时,去加载文件
    }

    void display() override {
        std::cout << "Display image: " << m_filename << std::endl;
    }

private:
    std::string m_filename;

    void loadFromDisk() {
        std::cout << "Loading image from disk: " << m_filename << std::endl;
    }
};

// 3️⃣ 代理对象(Proxy)
class ImageProxy : public Image {
public:
    explicit ImageProxy(const std::string& filename) : m_filename(filename), m_realImage(nullptr) {
        std::cout << "ImageProxy created\n";
    }

    ~ImageProxy() override {
        delete m_realImage;
    }

    void display() override {
        if (!m_realImage) {
            // 延迟创建真实对象
            m_realImage = new RealImage(m_filename);
        }
        m_realImage->display();
    }

private:
    std::string m_filename;
    RealImage* m_realImage;
};

// 4️⃣ Client 使用(完全无感知)
int main() {
    Image* image = new ImageProxy("test.png");

    std::cout << "Image created, not loaded yet.\n";

    image->display();  // 第一次才真正加载
    image->display();  // 第二次直接用

    delete image;
    return 0;
}

📌 核心点全在这:

  • 构造 ImageProxy没有 new RealImage
  • 只有真正 display() 才 new
  • 代理负责生命周期控制

什么时机用代理模式呢?

✔ 满足任意一条就值得考虑:

  • 对象创建很重
  • 访问需要权限 / 校验
  • 想控制真实对象生命周期
  • 想隐藏复杂性或远程调用

行为模式

责任链模式

定义

请求沿着一条"处理者链"往下传,每个处理者要么处理,要么交给下一个。

核心思想:👉 发送请求的对象 ≠ 处理请求的对象

责任链模式 ------ 类结构图

复制代码
                    +------------------------+
                    |   Handler (抽象处理者) |
                    +------------------------+
                    | - m_next : Handler*    |
                    +------------------------+
                    | + setNext(Handler*)   |
                    | + handleRequest() = 0 |
                    +-----------▲------------+
                                |
        ┌───────────────────────┼────────────────────────┐
        |                       |                        |
+-------------------+  +-------------------+  +-------------------+
| ConcreteHandlerA  |  | ConcreteHandlerB  |  | ConcreteHandlerC  |
+-------------------+  +-------------------+  +-------------------+
| + handleRequest() |  | + handleRequest() |  | + handleRequest() |
+-------------------+  +-------------------+  +-------------------+

结构重点(请你记住这 3 点)

  1. 每个 Handler 内部都持有一个 next 指针
  2. Client 只和 链头 打交道
  3. 请求是 "一层一层传",不是跳着找

C++示例

我们用一个很经典、很好理解的例子 :👉 请假审批流程

  • 组长:≤ 1 天
  • 经理:≤ 3 天
  • 总监:≤ 7 天
  • 再多就拒绝
C++ 复制代码
// 1️⃣ 抽象处理者(Handler)
#include <iostream>
using namespace std;

class LeaveHandler {
protected:
    LeaveHandler* m_next = nullptr;  // m_next:责任链的"链"

public:
    virtual ~LeaveHandler() = default;

    void setNext(LeaveHandler* next) {
        m_next = next;
    }

    virtual void handleRequest(int days) = 0;  // handleRequest:统一入口
};

// 2️⃣ 具体处理者
// 2.1 组长
class TeamLeader : public LeaveHandler {
public:
    void handleRequest(int days) override {
        if (days <= 1) {
            cout << "组长批准请假 " << days << " 天\n";
        } else if (m_next) {
            m_next->handleRequest(days);
        }
    }
};
// 2.2 经理
class Manager : public LeaveHandler {
public:
    void handleRequest(int days) override {
        if (days <= 3) {
            cout << "经理批准请假 " << days << " 天\n";
        } else if (m_next) {
            m_next->handleRequest(days);
        }
    }
};
// 2.3 总监
class Director : public LeaveHandler {
public:
    void handleRequest(int days) override {
        if (days <= 7) {
            cout << "总监批准请假 " << days << " 天\n";
        } else {
            cout << "请假 " << days << " 天,被拒绝 ❌\n";
        }
    }
};

// 3️⃣ Client 端(重点:new + 组链)
int main() {
    // 创建处理者对象
    LeaveHandler* leader = new TeamLeader();
    LeaveHandler* manager = new Manager();
    LeaveHandler* director = new Director();

    // 组装责任链
    leader->setNext(manager);
    manager->setNext(director);

    cout << "=== 请假 1 天 ===\n";
    leader->handleRequest(1);

    cout << "\n=== 请假 3 天 ===\n";
    leader->handleRequest(3);

    cout << "\n=== 请假 10 天 ===\n";
    leader->handleRequest(10);

    // 清理
    delete leader;
    delete manager;
    delete director;

    return 0;
}

运行时期关系图

复制代码
Client
  |
  ▼
TeamLeader  --->  Manager  --->  Director

Client 只调用 TeamLeader , 并不知道 Manager / Director 的存在

👉 责任链 = "谁能处理,谁上"

核心要点

责任链模式通过让多个处理对象形成一条链,请求沿链传递,直到某个对象处理它为止, 从而实现请求发送者与处理者的解耦

中介者模式

介绍

对象之间不再直接通信,而是通过一个中介者来协作, 从而把"网状依赖"变成"星状依赖"。

关键词:

👉 解耦对象之间的相互引用

👉 逻辑集中在中介者

类结构图

复制代码
                    +-------------------------+
                    |      Mediator           |  ← 抽象中介者
                    +-------------------------+
                    | + notify(sender, evt)  |
                    +------------▲------------+
                                 |
                implements       |
                                 |
                    +-------------------------+
                    |   ConcreteMediator      |
                    +-------------------------+
                    | - colleagueA*           |
                    | - colleagueB*           |
                    +-------------------------+
                    | + notify(...)           |
                    +------------▲------------+
                                 |
        ┌────────────────────────┼────────────────────────┐
        |                        |                        |
+-------------------+   +-------------------+   +-------------------+
|   Colleague       |   | ConcreteColleagueA|   | ConcreteColleagueB|
+-------------------+   +-------------------+   +-------------------+
| - mediator*       |   | + doA()           |   | + doB()           |
+-------------------+   | + receive()       |   | + receive()       |
| + send(event)     |   +-------------------+   +-------------------+
+-------------------+

🔑 结构记忆点(一定要记)

  1. Colleague 只认识 Mediator
  2. Mediator 认识所有 Colleague
  3. 业务协作逻辑 集中在 Mediator

我中介者 是知道我所有的 同事 是谁,并且交给我去让他们两者简介传递信息

而不同的同事,就只认识中介,并不知道要跟谁通信

C++代码示例

下面这个例子,并不涉及到同事之间的通信,但是会让自己的状态信息,让中介去处理,并更新自己

当然也可以更新同事,这里就不具体展开讲解了

c++ 复制代码
// 1️⃣ 抽象中介者
#include <iostream>
#include <string>
using namespace std;

class Colleague;

// 按理说:我中介 知道我所需要的 Colleague的所有具体的对象
class Mediator {
public:
    virtual ~Mediator() = default;
    virtual void notify(Colleague* sender, const string& event) = 0;
};


// 2️⃣ 抽象同事类, 自己只知道中介
class Colleague {
protected:
    Mediator* m_mediator;

public:
    explicit Colleague(Mediator* mediator) : m_mediator(mediator) {}

    virtual ~Colleague() = default;
};

// 3️⃣ 具体同事类
// 3.1 按钮
class Button : public Colleague {
public:
    using Colleague::Colleague;

    void click() {
        cout << "[Button] clicked\n";
        m_mediator->notify(this, "click");
    }

    void enable() {
        cout << "[Button] enabled\n";
    }
};

// 3.2文本框
class TextBox : public Colleague {
public:
    using Colleague::Colleague;

    void inputText(const string& text) {
        cout << "[TextBox] input: " << text << "\n";
        m_mediator->notify(this, "textChanged");
    }

    void clear() {
        cout << "[TextBox] cleared\n";
    }
};

// 4️⃣ 具体中介者(核心逻辑)
class DialogMediator : public Mediator {
private:
    Button* m_button;
    TextBox* m_textBox;

public:
    DialogMediator(Button* btn, TextBox* tb) : m_button(btn), m_textBox(tb) {}

    // 这里只让对应的 同事做自己应该做的状态,并不涉及同事之间的交流,当然也可以让他们更新,只不过通过我这个中介
    void notify(Colleague* sender, const string& event) override {
        if (sender == m_textBox && event == "textChanged") {
            m_button->enable();
        }
        else if (sender == m_button && event == "click") {
            m_textBox->clear();
        }
    }
};

// 5️⃣ Client(new + 组装关系)
int main() {
    DialogMediator* mediator = nullptr;

    Button* button = new Button(mediator);
    TextBox* textBox = new TextBox(mediator);

    mediator = new DialogMediator(button, textBox);

    // 重新注入 mediator
    button->m_mediator = mediator;
    textBox->m_mediator = mediator;

    textBox->inputText("Hello");
    button->click();

    delete button;
    delete textBox;
    delete mediator;
    return 0;
}

📌 注意这里

  • 所有协作逻辑都在中介者
  • Button / TextBox 完全不知道彼此

👉 中介者 = 把"群聊"变成"找群主"

一句话背诵版(稳)
中介者模式通过引入一个中介对象, 封装对象之间的交互,使对象不再直接引用彼此,从而降低系统耦合度。

策略模式

定义

定义一组算法,把每个算法封装成独立策略,它们可以互换,且不影响使用算法的上下文对象。

关键词:

👉 算法可替换

👉 消灭 if / switch

👉 行为解耦

类结构图

复制代码
                    +----------------------+
                    |    Strategy          |  ← 抽象策略
                    +----------------------+
                    | + execute()          |
                    +-----------▲----------+
                                |
          implements             |
                                |
        ┌───────────────────────┼───────────────────────┐
        |                       |                       |
+-------------------+  +-------------------+  +-------------------+
| StrategyA         |  | StrategyB         |  | StrategyC         |
+-------------------+  +-------------------+  +-------------------+
| + execute()       |  | + execute()       |  | + execute()       |
+-------------------+  +-------------------+  +-------------------+

                    +----------------------+
                    |     Context          |
                    +----------------------+
                    | - strategy : ptr     |
                    +----------------------+
                    | + setStrategy()      |
                    | + doWork()           |
                    +----------------------+

🔑 结构记忆点

  1. Context 持有 Strategy
  2. Strategy 之间互相不知道
  3. Context 不关心具体算法

C++示例

我们用一个工程中最常见的场景

👉 支付策略(微信 / 支付宝 / 银行卡)

c++ 复制代码
// 1️⃣ 抽象策略
#include <iostream>
using namespace std;

class PaymentStrategy {
public:
    virtual ~PaymentStrategy() = default;
    virtual void pay(int amount) = 0;
};


// 2️⃣ 具体策略
// 2.1 微信支付
class WeChatPay : public PaymentStrategy {
public:
    void pay(int amount) override {
        cout << "使用微信支付 " << amount << " 元\n";
    }
};

// 2.2 支付宝
class AliPay : public PaymentStrategy {
public:
    void pay(int amount) override {
        cout << "使用支付宝支付 " << amount << " 元\n";
    }
};

// 2.3 银行卡
class BankCardPay : public PaymentStrategy {
public:
    void pay(int amount) override {
        cout << "使用银行卡支付 " << amount << " 元\n";
    }
};


// 3️⃣ Context(重点)
class PaymentContext {
private:
    PaymentStrategy* m_strategy;

public:
    explicit PaymentContext(PaymentStrategy* strategy) : m_strategy(strategy) {}

    void setStrategy(PaymentStrategy* strategy) {
        m_strategy = strategy;
    }

    void pay(int amount) {
        if (m_strategy)
            m_strategy->pay(amount);
    }
};


// 4️⃣ Client(new + 切换策略)
int main() {
    PaymentStrategy* wechat = new WeChatPay();
    PaymentStrategy* alipay = new AliPay();
    PaymentStrategy* bank = new BankCardPay();

    PaymentContext context(wechat);
    context.pay(100);

    context.setStrategy(alipay);
    context.pay(200);

    context.setStrategy(bank);
    context.pay(300);

    delete wechat;
    delete alipay;
    delete bank;
    return 0;
}

📌 注意

  • Context 不 new 策略
  • 只"使用"策略

运行时期的对象关系图

yaml 复制代码
Client
  |
  ▼
PaymentContext
  |
  ▼
PaymentStrategy  --->  WeChatPay / AliPay / BankCardPay

切换算法 = 换策略对象

请求执行流程(时序): Client → Context → Strategy.execute()

需要知道:

策略模式通过将算法封装为独立对象,使它们可以互换, 从而让算法的变化不影响使用它们的上下文。

模板模式

定义

在父类中定义算法的整体骨架, 把某些步骤延迟到子类中实现,从而在不改变算法结构的前提下,重定义部分步骤

关键词:

👉 流程固定

👉 步骤可变

👉 继承 + 多态

类结构图

复制代码
                    +---------------------------+
                    |   AbstractClass           |
                    +---------------------------+
                    | + templateMethod() final  |  ← 模板方法
                    | - step1()                 |
                    | - step2() = 0             |  ← 可变步骤
                    | - step3()                 |
                    +-------------▲-------------+
                                  |
                implements        |
                                  |
                    +---------------------------+
                    |   ConcreteClass           |
                    +---------------------------+
                    | + step2()                 |
                    +---------------------------+

🔑 结构记忆点

  1. 模板方法在父类 (且不可以被重载 final)
  2. 执行顺序写死
  3. **子类只去填补 为 "空"**的方法

C++示例

c++ 复制代码
// 1️⃣ 抽象父类(模板定义者)
#include <iostream>
using namespace std;

class Beverage {
public:
    virtual ~Beverage() = default;

    // 模板方法:流程固定
    void make() final {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }

protected:
    void boilWater() {
        cout << "烧水\n";
    }

    virtual void brew() = 0;         // 可变步骤
    virtual void addCondiments() = 0; // 可变步骤

    void pourInCup() {
        cout << "倒入杯中\n";
    }
};


// 2️⃣ 具体子类
// 2.1 咖啡
class Coffee : public Beverage {
protected:
    void brew() override {
        cout << "冲泡咖啡\n";
    }

    void addCondiments() override {
        cout << "加糖和牛奶\n";
    }
};

// 2.2 茶
class Tea : public Beverage {
protected:
    void brew() override {
        cout << "泡茶叶\n";
    }

    void addCondiments() override {
        cout << "加柠檬\n";
    }
};

// 3️⃣ Client(new + 使用)
int main() {
    Beverage* coffee = new Coffee();
    Beverage* tea = new Tea();

    cout << "=== 制作咖啡 ===\n";
    coffee->make();

    cout << "\n=== 制作茶 ===\n";
    tea->make();

    delete coffee;
    delete tea;
    return 0;
}

📌 重点

  • make()模板方法
  • 子类 不能改流程
  • 只能实现 brew() / addCondiments()

运行期间执行流程

复制代码
make()
 ├─ boilWater()      (父类)
 ├─ brew()           (子类 Coffee)
 ├─ pourInCup()      (父类)
 └─ addCondiments()  (子类 Coffee)

📌 流程不变,行为可变

👉 算法控制权在父类

模板方法里常见的"进阶点"(工程常用)

1️⃣ 钩子方法(Hook)

c 复制代码
virtual bool customerWantsCondiments() {
    return true;
}
c 复制代码
void make() {
    boilWater();
    brew();
    pourInCup();
    if (customerWantsCondiments()) {
        addCondiments();
    }
}

子类可选择覆盖,也可不管。这个过程是通过 钩子方法来去确定的

核心

👉 模板方法 = 父类定流程,子类填细节

模板方法模式在父类中定义算法骨架, 将部分步骤延迟到子类实现, 从而在不改变算法结构的情况下扩展行为。

状态模式

定义

允许对象在其内部状态 改变时改变 它的行为, 看起来就像修改了对象的类。

关键词:

👉 行为随状态变

👉 状态自动切换

👉 消灭状态 if / switch

状态模式 类结构图

复制代码
                    +----------------------+
                    |       State          |  ← 抽象状态
                    +----------------------+
                    | + handle()           |
                    +-----------▲----------+
                                |
          implements            |
                                |
        ┌───────────────────────┼───────────────────────┐
        |                       |                       |
+-------------------+  +-------------------+  +-------------------+
| ConcreteStateA    |  | ConcreteStateB    |  | ConcreteStateC    |
+-------------------+  +-------------------+  +-------------------+
| + handle()        |  | + handle()        |  | + handle()        |
+-------------------+  +-------------------+  +-------------------+

                    +----------------------+
                    |       Context        |
                    +----------------------+
                    | - state : State*     |
                    +----------------------+
                    | + setState()         |
                    | + request()          |
                    +----------------------+

🔑 结构记忆点(非常重要)

  1. Context 持有 State
  2. State 决定下一个 State
  3. Client 不参与状态切换

C++示例

我们用一个非常典型的例子 :👉 自动售货机(待机 / 已投币 / 出货)

c++ 复制代码
// 1️⃣ 抽象状态
#include <iostream>
using namespace std;

class VendingMachine;

class State {
public:
    virtual ~State() = default;
    virtual void handle(VendingMachine* machine) = 0;
};

// 2️⃣ Context(状态持有者)
class VendingMachine {
private:
    State* m_state;

public:
    explicit VendingMachine(State* state) : m_state(state) {}

    void setState(State* state) {
        m_state = state;
    }

    void request() {
        m_state->handle(this);
    }
};

// 3️⃣ 具体状态类
// 3.1 待机状态
class IdleState : public State {
public:
    void handle(VendingMachine* machine) override;
};

// 3.2 已投币状态
class HasCoinState : public State {
public:
    void handle(VendingMachine* machine) override;
};

// 3.3 出货状态
class DispenseState : public State {
public:
    void handle(VendingMachine* machine) override;
};

// 4️⃣ 状态行为 + 状态切换(核心)
void IdleState::handle(VendingMachine* machine) {
    cout << "投币成功\n";
    machine->setState(new HasCoinState());
}

void HasCoinState::handle(VendingMachine* machine) {
    cout << "选择商品\n";
    machine->setState(new DispenseState());
}

void DispenseState::handle(VendingMachine* machine) {
    cout << "正在出货\n";
    machine->setState(new IdleState());
}

// 5️⃣ Client(new + 使用)
int main() {
    VendingMachine machine(new IdleState());

    machine.request(); // 投币
    machine.request(); // 选择商品
    machine.request(); // 出货
    machine.request(); // 再次投币

    return 0;
}

📌 注意

  • Context 只转发 ; 不写 if / switch
  • 状态自己决定切换, Context 不关心"切到哪"

每个具体的状态,利用状态机在处理完毕的时候,去切换状态到下一个状态

状态机 每 执行一次 , 就会切换一次状态
运行期间的状态流程图

复制代码
IdleState  <-------------|	
    ↓ 投币				|
HasCoinState			  |
    ↓ 选择商品			   |
DispenseState			  |
    ↓ 出货完成			   |
IdleState				  |
	↓---------------------|

📌 行为 = 状态类的方法

核心

状态模式通过将 状态 封装为独立对象,使对象在 不同状态下 表现出不同的行为,并由状态对象自身负责状态转换

状态机去执行具体的 某种状态下的行为,这种状态的切换 由 具体的状态自己负责

观察者模式

定义

定义对象之间的一对多依赖关系,当一个对象状态发生变化时, 所有依赖它的对象都会收到通知并自动更新。

关键词:

👉 发布 / 订阅

👉 广播通知

👉 松耦合

类结构图

复制代码
                +----------------------+
                |      Subject         |  ← 被观察者(抽象)
                +----------------------+
                | + attach(Observer*)  |
                | + detach(Observer*)  |
                | + notify()           |
                +-----------▲----------+
                            |
            implements      |
                            |
                +----------------------+
                |   ConcreteSubject    |
                +----------------------+
                | - state              |
                +----------------------+
                | + getState()         |
                | + setState()         |
                +-----------▲----------+
                            |
                            |
        ┌───────────────────┼───────────────────┐
        |                   |                   |
+-------------------+ +-------------------+ +-------------------+
|   Observer        | | ConcreteObserverA | | ConcreteObserverB |
+-------------------+ +-------------------+ +-------------------+
| + update()        | | + update()        | | + update()        |
+-------------------+ +-------------------+ +-------------------+

🔑 结构记忆点(非常重要)

  1. Subject 持有 Observer 列表
  2. Observer 只关心 Subject
  3. 通知是"广播",不是定向

c++示例

我们用一个特别经典、非常好理解的例子 : 👉 股票价格变化 → 多个客户端同步更新

c++ 复制代码
// 1️⃣ 抽象观察者
#include <iostream>
#include <vector>
using namespace std;

class Observer {
public:
    virtual ~Observer() = default;
    virtual void update(int price) = 0;
};

// 2️⃣ 抽象被观察者(Subject)
class Subject {
public:
    virtual ~Subject() = default;
    virtual void attach(Observer* obs) = 0;
    virtual void detach(Observer* obs) = 0;
    virtual void notify() = 0;
};

// 3️⃣ 具体被观察者
class Stock : public Subject {
private:
    int m_price = 0;
    vector<Observer*> m_observers;

public:
    void attach(Observer* obs) override {
        m_observers.push_back(obs);
    }

    void detach(Observer* obs) override {
        m_observers.erase(
            remove(m_observers.begin(), m_observers.end(), obs),
            m_observers.end());
    }

    void setPrice(int price) {
        m_price = price;
        notify();
    }

    int getPrice() const {
        return m_price;
    }

    void notify() override {
        for (auto* obs : m_observers) {
            obs->update(m_price);
        }
    }
};

// 4️⃣ 具体观察者
// 4.1 手机客户端
class MobileClient : public Observer {
public:
    void update(int price) override {
        cout << "[手机] 股票价格更新为: " << price << endl;
    }
};

// 4.2 网页客户端
class WebClient : public Observer {
public:
    void update(int price) override {
        cout << "[网页] 股票价格更新为: " << price << endl;
    }
};

// 5️⃣ Client(new + 组装关系)
int main() {
    Stock* stock = new Stock();

    Observer* mobile = new MobileClient();
    Observer* web = new WebClient();

    stock->attach(mobile);
    stock->attach(web);

    stock->setPrice(100);
    stock->setPrice(120);

    delete mobile;
    delete web;
    delete stock;
    return 0;
}

📌 关键点

  • Subject 不知道 Observer 的具体类型 , 只是通过notify调用 update

运行期间关系图

复制代码
           Stock (Subject)
             |
     ┌───────┼────────┐
     ▼       ▼        ▼
 Mobile   WebClient  ...
Observer

// 通知流程(时序)
setPrice()
   ↓
notify()
   ↓
ObserverA.update()
ObserverB.update()
ObserverC.update()

📌 一变,多响

✔ 没有顺序保证

✔ 没有返回值依赖

总结:观察者模式定义了一种一对多的依赖关系,当被观察对象状态发生变化时,所有观察者都会收到通知并自动更新。

备忘录模式

定义

在不破坏对象封装性的前提下,捕获并保存对象的 内部状态,以便以后可以 恢复到该状态。

关键词:

👉 快照 / 回滚

👉 封装不被破坏

👉 状态由外部保存

类结构图

复制代码
                 +----------------------+
                 |     Originator       |  ← 原发器(状态拥有者)
                 +----------------------+
                 | - state              |
                 +----------------------+
                 | + createMemento()    |
                 | + restore(Memento)   |
                 +-----------▲----------+
                             |
                             | creates / uses
                             |
                 +----------------------+
                 |      Memento         |  ← 备忘录
                 +----------------------+
                 | - state              |
                 +----------------------+
                 | (对 Caretaker 不可见) |
                 +----------------------+

                 +----------------------+
                 |     Caretaker        |  ← 管理者
                 +----------------------+
                 | - memento            |
                 +----------------------+

🔑 结构记忆点(非常重要)

  1. 状态只存在于 Originator
  2. Caretaker 只保存,不读取
  3. Memento 是"封装的快照"

C++示例

👉 文本编辑器的撤销功能

c++ 复制代码
// 1️⃣ 备忘录类(只存状态)
#include <iostream>
#include <string>
using namespace std;

class Memento {
private:
    string m_text;

public:
    explicit Memento(const string& text) : m_text(text) {}

    string getText() const {
        return m_text;
    }
};

// 2️⃣ 原发器(状态拥有者)
class TextEditor {
private:
    string m_text;

public:
    void setText(const string& text) {
        m_text = text;
        cout << "当前文本: " << m_text << endl;
    }

    Memento* createMemento() {
        return new Memento(m_text);
    }

    void restore(Memento* memento) {
        m_text = memento->getText();
        cout << "恢复文本: " << m_text << endl;
    }
};

// 3️⃣ 管理者(Caretaker)
class History {
private:
    Memento* m_memento = nullptr;

public:
    void save(Memento* memento) {
        m_memento = memento;
    }

    Memento* get() {
        return m_memento;
    }
};

// 4️⃣ Client(new + 使用)
int main() {
    TextEditor editor;
    History history;

    editor.setText("Hello");
    history.save(editor.createMemento()); // 保存快照

    editor.setText("Hello World");
    editor.setText("Hello World!!!");

    cout << "\n=== Undo ===\n";
    editor.restore(history.get()); // 回滚

    return 0;
}

📌 注意

  • 备忘录类的:状态是私有的, 外部无法修改
  • 只有 TextEditor 能读 Memento, 外部无法窥探内部状态
  • Caretaker 的职责只有一个:保存

运行期间对象关系图

复制代码
Client
  |
  ▼
Caretaker ----> Memento
                    ▲
                    |
               Originator

五、撤销流程(一步一步看)
1. Originator.createMemento()
2. Caretaker 保存 Memento
3. Originator 状态变化
4. Originator.restore(Memento)

✔ 没有 if / switch

✔ 没有状态泄漏

工程中的真实使用场景

  • 文本编辑器 Undo / Redo
  • IDE 历史记录
  • 游戏存档
  • 配置回滚

备忘录模式在不破坏封装的前提下,捕获并保存对象的内部状态, 使对象能够恢复到之前的状态。

命令模式

定义

把"请求"封装成一个对象,从而让你用 不同的请求、队列、撤销、日志等方式 来参数化调用者

再直白点:

  • 调用者(Invoker):不关心"怎么做"
  • 命令(Command):知道"做什么"
  • 接收者(Receiver):真正干活的人

📌 核心解耦点:
"谁发命令" 和 "谁执行命令" 解耦

应用场景

你会在这些场景中非常适合用它:

  • GUI 按钮(Qt 里特别典型)
  • 撤销 / 重做(Undo / Redo)
  • 宏命令(一次执行多个操作)
  • 日志 / 事务 / 队列化请求

👉 Qt 的 QAction + slot,本质上就很像命令模式

角色划分

角色 含义
Command 抽象命令接口
ConcreteCommand 具体命令
Receiver 真正执行动作的对象
Invoker 调用命令的对象
Client 创建并组装对象

类结构图

复制代码
        +----------------+
        |    Command     |  <----- 抽象命令
        |----------------|
        | +execute()     |
        +----------------+
                 ▲
                 |
        +----------------------+
        | ConcreteCommand      |
        |----------------------|
        | - receiver           |
        | +execute()           |
        +----------------------+
                 |
                 v
        +----------------+
        |   Receiver     |  <----- 真正干活
        |----------------|
        | +action()      |
        +----------------+

        +----------------+
        |   Invoker      |  <----- 调用者
        |----------------|
        | - command      |
        | +click()       |
        +----------------+

📌 Invoker 完全不知道 Receiver 的存在

C++示例

我们用一个**"遥控器控制灯"**的经典例子

c++ 复制代码
// 1️⃣ 抽象命令
class Command {
public:
    virtual ~Command() {}
    virtual void execute() = 0;
};

// 2️⃣ 接收者(真正干活的人)
#include <iostream>
using namespace std;

class Light {
public:
    void on() {
        cout << "灯被打开了" << endl;
    }

    void off() {
        cout << "灯被关闭了" << endl;
    }
};

// 3️⃣ 具体命令(封装请求)
// 3.1 开启
class LightOnCommand : public Command {
public:
    LightOnCommand(Light* light) : m_light(light) {}

    void execute() override {
        m_light->on();
    }

private:
    Light* m_light;
};

// 3.2关闭
class LightOffCommand : public Command {
public:
    LightOffCommand(Light* light) : m_light(light) {}

    void execute() override {
        m_light->off();
    }

private:
    Light* m_light;
};

// 4️⃣ 调用者(Invoker)
class RemoteControl {
public:
    RemoteControl(Command* command) : m_command(command) {}

    void pressButton() {
        m_command->execute();
    }

private:
    Command* m_command;
};

// 5️⃣ Client(组装对象)
int main() {
    // 接收者
    Light* livingRoomLight = new Light();

    // 命令
    Command* lightOn = new LightOnCommand(livingRoomLight);
    Command* lightOff = new LightOffCommand(livingRoomLight);

    // 调用者, 通过命令,去让这个命令做一些工作, 而这个命名会让这个ligit去给一个命令,去做具体的任务 
    RemoteControl* remote1 = new RemoteControl(lightOn);
    RemoteControl* remote2 = new RemoteControl(lightOff);

    remote1->pressButton();  // 打开灯
    remote2->pressButton();  // 关闭灯

    // 释放资源
    delete remote1;
    delete remote2;
    delete lightOn;
    delete lightOff;
    delete livingRoomLight;

    return 0;
}
设计模式 Qt 中的影子
Command QAction
Invoker QPushButton / QMenu
Receiver 业务对象
execute slot

命令模式 = 把"函数调用"升级成"对象"

访问者模式

定义

把"对一组对象的操作"抽离出来,放到访问者中,而不是写在对象里

  • 对象结构稳定(类很少改)
  • 操作经常变(分析 / 统计 / 导出 / 打印 / 校验)

👉 那就用访问者

为何需要访问者

假设你有这些类:

复制代码
Circle
Rectangle
Triangle

现在你要:

  • 计算面积
  • 打印信息
  • 导出 JSON
  • 做碰撞检测
  • 生成 DXF

❌ 不用访问者:

👉 每加一种"操作",每个类都要改

✔️ 用访问者:

👉 类不动,只加 Visitor

访问者模式最关键的一点:运行时同时根据「元素类型」和「访问者类型」分派函数

主要是依靠这句:element->accept(visitor);

结构图

复制代码
                +----------------+
                |   Visitor      |  <---- 抽象访问者
                |----------------|
                | visit(A)       |
                | visit(B)       |
                +----------------+
                         ▲
                         |
        +--------------------------------+
        | ConcreteVisitor                |
        +--------------------------------+

        +----------------+
        |   Element      |  <---- 抽象元素
        |----------------|
        | accept(Visitor)|
        +----------------+
                 ▲
     +-----------+-----------+
     |                       |
+----------+            +----------+
| ElementA |            | ElementB |
|----------|            |----------|
| accept() |            | accept() |
+----------+            +----------+

c++示例

我们用一个几何图形 + 面积 / 打印访问者的例子

c++ 复制代码
// 1️⃣ 前向声明
class Circle;
class Rectangle;

// 2️⃣ 抽象访问者
class ShapeVisitor {
public:
    virtual ~ShapeVisitor() {}
    virtual void visit(Circle* circle) = 0;
    virtual void visit(Rectangle* rect) = 0;
};

// 3️⃣ 抽象元素
class Shape {
public:
    virtual ~Shape() {}
    virtual void accept(ShapeVisitor* visitor) = 0;
};

// 4️⃣ 具体元素
// 4.1 Circle
class Circle : public Shape {
public:
    Circle(double r) : m_radius(r) {}

    double radius() const { return m_radius; }

    void accept(ShapeVisitor* visitor) override {
        visitor->visit(this);   // 👈 关键
    }

private:
    double m_radius;
};

// 4.2Rectangle
class Rectangle : public Shape {
public:
    Rectangle(double w, double h)
        : m_width(w), m_height(h) {}

    double width() const { return m_width; }
    double height() const { return m_height; }

    void accept(ShapeVisitor* visitor) override {
        visitor->visit(this);
    }

private:
    double m_width;
    double m_height;
};

// 5️⃣ 具体访问者 ①:面积计算
#include <iostream>
using namespace std;

class AreaVisitor : public ShapeVisitor {
public:
    void visit(Circle* circle) override {
        double area = 3.14159 * circle->radius() * circle->radius();
        cout << "Circle area = " << area << endl;
    }

    void visit(Rectangle* rect) override {
        double area = rect->width() * rect->height();
        cout << "Rectangle area = " << area << endl;
    }
};

// 6️⃣ 具体访问者 ②:信息打印
class PrintVisitor : public ShapeVisitor {
public:
    void visit(Circle* circle) override {
        cout << "Circle, radius = " << circle->radius() << endl;
    }

    void visit(Rectangle* rect) override {
        cout << "Rectangle, width = "
             << rect->width()
             << ", height = "
             << rect->height()
             << endl;
    }
};

// 7️⃣ Client(new + 构造)
#include <vector>

int main() {
    vector<Shape*> shapes;

    shapes.push_back(new Circle(5.0));
    shapes.push_back(new Rectangle(4.0, 6.0));

    ShapeVisitor* areaVisitor = new AreaVisitor();
    ShapeVisitor* printVisitor = new PrintVisitor();

    for (auto shape : shapes) {
        shape->accept(printVisitor);
        shape->accept(areaVisitor);
    }

    // 清理
    delete areaVisitor;
    delete printVisitor;

    for (auto shape : shapes)
        delete shape;

    return 0;
}

总结

✅ 优点

  • 新增"操作"极其方便
  • 符合 单一职责原则
  • 非常适合 AST / OCC 拓扑遍历 / 文档模型

❌ 缺点(劝退点)

  • 新增 Element 很痛苦
    • 要改所有 Visitor
  • 类之间耦合强(Visitor 依赖所有 Element)
  • 对新手不友好(双分派)

✔️ 用它

  • 对象结构 稳定
  • 操作 经常变
  • 编译器 / 解析器 / 几何拓扑遍历

❌ 别用它

  • 类结构经常变
  • 只是简单多态就能搞定
  • 访问逻辑很少

访问者模式 = 把"算法"从"数据结构"里剥离出来

解释器模式

定义

定义:说人话:

  • 你先定义一套 规则 / 语法
  • 再用一堆对象 "解释"表达式
  • 最终得到一个结果

使用场景

  • 数学表达式:1 + 2 - 3
  • 规则引擎:age > 18 AND vip == true
  • SQL where 子集
  • 配置规则 / 权限表达式
  • 编译器里的 AST 解释执行

👉 语法固定 + 反复解释

结构图

c++ 复制代码
                 +----------------------+
                 |   AbstractExpression |
                 |----------------------|
                 | interpret(Context)   |
                 +-----------▲----------+
                             |
           +-----------------+-----------------+
           |                                   |
+-----------------------+        +------------------------+
| TerminalExpression    |        | NonTerminalExpression  |
|-----------------------|        |------------------------|
| interpret()           |        | interpret()            |
+-----------------------+        +------------------------+
                                         ▲
                                         |
                              +-----------------------+
                              |  Expression组合结构    |
                              +-----------------------+

                 +----------------------+
                 |      Context         |
                 |----------------------|
                 | 输入 / 状态 / 变量表   |
                 +----------------------+

C++示例

以最经典的加减法表达式为例:去解释这个表达式:(5 + 3) - 2

c++ 复制代码
// 1️⃣ Context(上下文,可选),这里我们不放变量,简化成直接返回值。
class Context {
    // 这里可以放变量表、环境信息
};

// 2️⃣ 抽象表达式
class Expression {
public:
    virtual ~Expression() {}
    virtual int interpret(Context& ctx) = 0;
};

// 3️⃣ 终结符表达式(数字)
class NumberExpression : public Expression {
public:
    explicit NumberExpression(int value)
        : m_value(value) {}

    int interpret(Context&) override {
        return m_value;
    }

private:
    int m_value;
};

// 4️⃣ 非终结符表达式(加法)
class AddExpression : public Expression {
public:
    AddExpression(Expression* left, Expression* right)
        : m_left(left), m_right(right) {}

    ~AddExpression() {
        delete m_left;
        delete m_right;
    }

    int interpret(Context& ctx) override {
        return m_left->interpret(ctx) + m_right->interpret(ctx);
    }

private:
    Expression* m_left;
    Expression* m_right;
};

// 5️⃣ 非终结符表达式(减法)
class SubExpression : public Expression {
public:
    SubExpression(Expression* left, Expression* right)
        : m_left(left), m_right(right) {}

    ~SubExpression() {
        delete m_left;
        delete m_right;
    }

    int interpret(Context& ctx) override {
        return m_left->interpret(ctx) - m_right->interpret(ctx);
    }

private:
    Expression* m_left;
    Expression* m_right;
};

// 6️⃣ Client(new + 构造 AST)
#include <iostream>
using namespace std;

int main() {
    Context ctx;

    // 构造表达式树:(5 + 3) - 2
    Expression* expression =
        new SubExpression(
            new AddExpression(
                new NumberExpression(5),
                new NumberExpression(3)
            ),
            new NumberExpression(2)
        );

    cout << "Result = " << expression->interpret(ctx) << endl;

    delete expression;
    return 0;
}

执行过程:

复制代码
SubExpression
 ├─ AddExpression
 │   ├─ Number(5)
 │   └─ Number(3)
 └─ Number(2)
执行顺序:

Number(5) → 5

Number(3) → 3

Add → 8

Number(2) → 2

Sub → 6

总结

解释器模式为一门简单语言定义语法表示,并定义解释器来解释语言中的句子。

迭代器模式

定义

提供一种方法顺序访问一个聚合对象中的各个元素,而不暴露其内部表示。

翻成工程话:

  • 数据怎么存的,你别管
  • 我给你一个"游标"
  • 你只管 next / hasNext

使用迭代器的原因:

不用迭代器,你会写出这样的代码:

复制代码
for (int i = 0; i < arrSize; ++i) {
    // 访问数组
}

但如果内部结构变成:

  • 链表?
  • 树?
  • 跳表?
  • OCC 的拓扑结构?

❌ Client 全崩

✔️ 迭代器:访问逻辑不变

结构图

复制代码
            +----------------------+
            |      Iterator        |
            |----------------------|
            | hasNext()            |
            | next()               |
            +-----------▲----------+
                        |
            +----------------------+
            |  ConcreteIterator    |
            +----------------------+

            +----------------------+
            |     Aggregate        |
            |----------------------|
            | createIterator()     |
            +-----------▲----------+
                        |
            +----------------------+
            | ConcreteAggregate    |
            |----------------------|
            | 内部数据结构           |
            +----------------------+

C++示例

我们做一个简单数组容器,但 Client 完全不知道它是数组。

c++ 复制代码
// 1️⃣ 迭代器接口
class Iterator {
public:
    virtual ~Iterator() {}
    virtual bool hasNext() = 0;
    virtual int next() = 0;
};

// 2️⃣ 聚合接口
class Aggregate {
public:
    virtual ~Aggregate() {}
    virtual Iterator* createIterator() = 0;
};

// 3️⃣ 具体聚合(内部是数组)
class IntCollection : public Aggregate {
public:
    IntCollection(int* data, int size)
        : m_data(data), m_size(size) {}

    Iterator* createIterator() override;

    int get(int index) const {
        return m_data[index];
    }

    int size() const {
        return m_size;
    }

private:
    int* m_data;
    int m_size;
};

// 4️⃣ 具体迭代器
class IntIterator : public Iterator {
public:
    explicit IntIterator(IntCollection* collection)
        : m_collection(collection), m_index(0) {}

    bool hasNext() override {
        return m_index < m_collection->size();
    }

    int next() override {
        return m_collection->get(m_index++);
    }

private:
    IntCollection* m_collection;
    int m_index;
};

// 5️⃣ 关联 Iterator 和 Aggregate
Iterator* IntCollection::createIterator() {
    return new IntIterator(this);
}

// 6️⃣ Client 使用(完全不知道内部结构)
#include <iostream>
using namespace std;

int main() {
    int data[] = {1, 3, 5, 7, 9};

    Aggregate* collection = new IntCollection(data, 5);
    Iterator* it = collection->createIterator();

    while (it->hasNext()) {
        cout << it->next() << " ";
    }

    cout << endl;

    delete it;
    delete collection;
    return 0;
}

👉 STL 是迭代器模式的教科书级实现

c 复制代码
for (auto it = v.begin(); it != v.end(); ++it) {
    cout << *it;
}

优缺点:

✅ 优点

  • 解耦遍历与数据结构
  • 支持多种遍历方式
  • 统一访问接口

❌ 缺点

  • 类数量变多
  • 简单结构用它显得"重"

总结

迭代器模式提供一种统一方式顺序访问聚合对象的元素,而不暴露其内部结构。


相关推荐
__万波__2 小时前
二十三种设计模式(十五)--访问者模式
java·设计模式·访问者模式
阿闽ooo13 小时前
外观模式:从家庭电源控制看“简化接口“的设计智慧
c++·设计模式·外观模式
Geoking.14 小时前
【UML】面向对象中类与类之间的关系详解
设计模式·uml
希望_睿智20 小时前
实战设计模式之中介者模式
c++·设计模式·架构
有一个好名字1 天前
设计模式-观察者模式
观察者模式·设计模式
青柠代码录1 天前
【设计模式】A1-单例模式
单例模式·设计模式
阿闽ooo2 天前
深入浅出适配器模式:从跨国插头适配看接口兼容的艺术
c++·设计模式·适配器模式
Kiyra2 天前
WebSocket vs HTTP:为什么 IM 系统选择长连接?
分布式·websocket·网络协议·http·设计模式·系统架构·wpf