一、设计模式
设计模式(Design Patterns)是软件开发中反复出现问题的解决方案的通用描述 。
它是经过总结、提炼的高效代码结构和设计方案 ,帮助开发者写出更灵活、可维护和可扩展的代码。
| 优点 | 注意点 | 
|---|---|
| 规范代码结构,提高开发效率 | 设计模式不是银弹,需结合实际使用 | 
| 促进代码复用和灵活扩展 | 滥用设计模式会导致过度设计 | 
| 便于团队沟通和代码维护 | 理解设计模式背后的设计原则更重要 | 
二、设计模式应用原则
| 原则 | 英文全称 | 核心思想 | 
|---|---|---|
| 单一职责原则(SRP) | Single Responsibility Principle | 一个类只负责一项职责,如变化只因一个原因而发生 | 
| 开闭原则(OCP) | Open/Closed Principle | 对扩展开放,对修改关闭,鼓励使用抽象与继承 | 
| 里氏替换原则(LSP) | Liskov Substitution Principle | 子类对象能替换父类对象而不影响程序正确性 | 
| 接口隔离原则(ISP) | Interface Segregation Principle | 不应强迫用户依赖他们不使用的方法 | 
| 依赖倒置原则(DIP) | Dependency Inversion Principle | 依赖于抽象而非具体实现(低层依赖高层) | 
| 合成复用原则(CRP) | Composite Reuse Principle | 优先使用对象组合而非类继承 | 
| 最少知识原则(LoD) | Law of Demeter | 只与直接朋友通信,降低类之间耦合 | 
| 迪米特法则(Demeter) | Law of Demeter(LoD 的别称) | 同上,只交互需要交互的对象 | 
三、设计模式的分类
设计模式一般分为三大类:
| 类别 | 作用 | 代表模式举例 | 
|---|---|---|
| 创建型模式 | 关注对象的创建,简化对象创建过程 | 单例(Singleton)、工厂(Factory)、抽象工厂(Abstract Factory)、建造者(Builder)、原型(Prototype) | 
| 结构型模式 | 关注对象和类的组合 ,实现高效的结构设计 | 适配器(Adapter)、装饰器(Decorator)、代理(Proxy)、桥接(Bridge)、组合(Composite)、享元(Flyweight)、外观(Facade) | 
| 行为型模式 | 关注对象之间的通信和职责分配 | 观察者(Observer)、策略(Strategy)、命令(Command)、状态(State)、职责链(Chain of Responsibility)、迭代器(Iterator)、中介者(Mediator)、备忘录(Memento) | 
常见设计模式有单例模式、工厂模式、观察者模式、策略模式、代理模式、装饰器模式等。
四、常见设计模式------单例模式(Singleton Pattern)
1. 概念
单例模式 (Singleton Pattern)是一种创建型设计模式,目的是:
确保一个类只有一个实例,并提供一个全局访问点。
- 单例模式提供 全局唯一实例控制,是一种非常常用的基础模式;
 - 在多线程环境下注意加锁 或使用现代 C++ 静态变量机制;
 - 避免滥用,防止造成代码耦合和测试困难。
 
2. 使用场景
适用于以下场景:
| 场景描述 | 示例 | 
|---|---|
| 程序中只需要一个实例 | 日志记录器、线程池、数据库连接池 | 
| 全局共享访问 | 配置管理器、计数器、注册表 | 
| 控制资源访问 | 限制类实例个数,控制某些资源(如IO、GPU等) | 
3. 核心特点
- 构造函数私有化,防止外部创建对象。
 - 提供静态方法,返回唯一实例。
 - 类中保存唯一实例的静态指针。
 
4. C++ 中的经典实现(线程安全 + 懒汉式)
            
            
              cpp
              
              
            
          
          #include <iostream>
using namespace std;
#include <mutex>
class Singleton {
private:
    // 构造函数私有,防止外部构造
    Singleton()
    {
        cout << "构造 Singleton 对象" << endl;
    }
    // 禁用拷贝构造和赋值操作
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    static Singleton* instance;    // 静态指针
    static std::mutex mtx;         // 线程安全锁
public:
    static Singleton* getInstance()
    {
        // 双重检查锁定(Double-Check Locking)
        if (instance == nullptr)
        {
            lock_guard<mutex> lock(mtx); // 线程锁
            if (instance == nullptr)
            {
                instance = new Singleton();
            }
        }
        return instance;
    }
    void show()
    {
        cout << "这是 Singleton 实例" << endl;
    }
};
// 初始化静态成员
Singleton* Singleton::instance = nullptr;
mutex Singleton::mtx;
// 测试
int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();
    s1->show();
    if (s1 == s2)
        cout << "两个实例相同,单例模式生效!" << endl;
    return 0;
}
        注意:
= delete是 C++11 引入的一种机制,用来显式标记某个函数(包括构造、赋值、析构、普通函数)不允许使用。- 如果调用被 
= delete的函数,编译时就会报错,这比写成私有函数 + 空实现更安全、更清晰。 
5. 变体说明
| 实现方式 | 是否线程安全 | 是否懒加载 | 特点 | 
|---|---|---|---|
| 懒汉式(如上) | ✅ | ✅ | 第一次调用时创建实例,性能较优 | 
| 饿汉式(静态变量) | ✅ | ❌ | 程序加载时即创建,简单但可能浪费资源 | 
| C++11 静态局部变量 | ✅(自动线程安全) | ✅ | 推荐:C++11后局部静态变量是线程安全的 | 
五、工厂模式(Factory Pattern)
1. 概念
工厂模式 是一种常见的创建型设计模式,核心目的是:
将对象的创建逻辑从使用者中解耦,由"工厂"统一创建对象。
2. 主要分类
| 模式名称 | 简要说明 | 
|---|---|
| 简单工厂模式 | 一个工厂类决定创建哪一种产品类 | 
| 工厂方法模式 | 每个产品由一个具体工厂类负责创建 | 
| 抽象工厂模式 | 生产多个产品族(多个产品等级结构),创建一组相关对象 | 
3. 适用场景
- 对象创建过程复杂或变化频繁;
 - 代码中存在大量 
new操作,难以维护; - 系统要根据不同条件动态决定创建哪一类对象。
 
4. 示例------工厂方法模式(Factory Method Pattern)
场景:不同的图形类(Circle, Rectangle),由对应的工厂类生成。
产品抽象类:
            
            
              cpp
              
              
            
          
          class Shape {
public:
    virtual void draw() = 0; // 纯虚函数
    virtual ~Shape() = default;
};
        具体产品类:
            
            
              cpp
              
              
            
          
          class Circle : public Shape {
public:
    void draw() override 
    {
        std::cout << "绘制圆形" << std::endl;
    }
};
class Rectangle : public Shape {
public:
    void draw() override 
    {
        std::cout << "绘制矩形" << std::endl;
    }
};
        工厂抽象类:
            
            
              cpp
              
              
            
          
          class ShapeFactory {
public:
    virtual Shape* createShape() = 0; // 创建产品接口
    virtual ~ShapeFactory() = default;
};
        具体工厂类:
            
            
              cpp
              
              
            
          
          class CircleFactory : public ShapeFactory {
public:
    Shape* createShape() override 
    {
        return new Circle();
    }
};
class RectangleFactory : public ShapeFactory {
public:
    Shape* createShape() override 
    {
        return new Rectangle();
    }
};
        客户端使用:
            
            
              cpp
              
              
            
          
          int main() {
    ShapeFactory* factory;
    factory = new CircleFactory();
    Shape* circle = factory->createShape();
    circle->draw();
    delete circle;
    delete factory;
    factory = new RectangleFactory();
    Shape* rectangle = factory->createShape();
    rectangle->draw();
    delete rectangle;
    delete factory;
    return 0;
}
        5. 优缺点分析
| 优点 | 缺点 | 
|---|---|
| 封装对象创建,调用者无需关心构造细节 | 每新增一个产品类就需要新增一个工厂类(类爆炸) | 
| 易于扩展 ,遵循开闭原则 | 简单场景下可能显得过度设计 | 
| 可以灵活切换不同产品,支持多态创建和调用 | 抽象层次增加,系统结构更复杂 | 
六、观察者模式(Observer Pattern)
1. 概念
观察者模式 是一种行为型模式 ,用于建立一种一对多的依赖关系:
当一个对象(主题/被观察者 )的状态发生变化时,所有依赖于它的对象 (观察者)都会自动收到通知并更新。
2. 应用场景
| 场景 | 示例 | 
|---|---|
| 状态变化需要通知其他对象 | 图形界面事件(按钮点击) | 
| 发布-订阅系统 | 消息队列、邮件通知、新闻订阅系统 | 
| 数据模型与视图同步 | MVC 模式中的 Model 和 View | 
3. 结构组成
| 角色 | 职责说明 | 
|---|---|
| Subject(主题) | 维护观察者列表、添加/移除/通知观察者 | 
| Observer(观察者) | 接收通知并作出反应 | 
| ConcreteSubject | 实际的主题,状态发生变化时通知观察者 | 
| ConcreteObserver | 实际观察者,实现更新逻辑 | 
4. C++ 示例代码
场景:气象站(WeatherStation)数据变化,通知多个显示设备(观察者)。
抽象观察者接口:
            
            
              cpp
              
              
            
          
          class Observer {
public:
    virtual void update(float temperature) = 0;
    virtual ~Observer() = default;
};
        主题(Subject)接口:
            
            
              cpp
              
              
            
          
          #include <vector>
class Subject {
public:
    virtual void attach(Observer* observer) = 0;
    virtual void detach(Observer* observer) = 0;
    virtual void notify() = 0;
    virtual ~Subject() = default;
};
        具体主题类:
            
            
              cpp
              
              
            
          
          class WeatherStation : public Subject {
private:
    std::vector<Observer*> observers;
    float temperature;
public:
    void setTemperature(float temp) 
    {
        temperature = temp;
        notify(); // 数据变化时,通知所有观察者
    }
    void attach(Observer* observer) override 
    {
        observers.push_back(observer);
    }
    void detach(Observer* observer) override 
    {
        observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
    }
    void notify() override {
        for (Observer* o : observers) 
        {
            o->update(temperature);
        }
    }
};
        具体观察者类:
            
            
              cpp
              
              
            
          
          class PhoneDisplay : public Observer {
public:
    void update(float temperature) override 
    {
        std::cout << "[Phone] 当前温度:" << temperature << "°C" << std::endl;
    }
};
class LEDDisplay : public Observer {
public:
    void update(float temperature) override 
    {
        std::cout << "[LED] 显示屏温度:" << temperature << "°C" << std::endl;
    }
};
        客户端使用:
            
            
              cpp
              
              
            
          
          int main() {
    WeatherStation station;
    PhoneDisplay phone;
    LEDDisplay led;
    station.attach(&phone);
    station.attach(&led);
    station.setTemperature(25.5f);
    station.setTemperature(30.2f);
    return 0;
}
        5. 优缺点分析
| 优点 | 缺点 | 
|---|---|
| 解耦 :主题和观察者之间松散耦合 | 可能出现通知链过长,影响性能 | 
| 易扩展:可动态添加/删除观察者 | 无法保证通知顺序,某些观察者可能对顺序敏感 | 
| 符合"开闭原则":新增观察者不改动主题类 | 如果观察者太多,频繁通知可能带来性能开销 | 
6. 实际应用
- Qt 信号槽机制;
 - GUI 框架(按钮监听器);
 - 消息发布/订阅(如 Kafka、RabbitMQ);
 - Excel 单元格间依赖(值变化时联动)。
 
七、代理模式(Proxy Pattern)
1. 概念
代理模式 属于结构型设计模式,主要作用是:
为其他对象提供一种"代理"以控制对该对象的访问。
即通过一个中介(代理对象)来间接访问目标对象 ,可以增加访问控制、延迟加载、资源控制等功能。
2. 适用场景
| 场景描述 | 示例 | 
|---|---|
| 远程代理(Remote Proxy) | 远程方法调用,如 RPC 框架 | 
| 虚拟代理(Virtual Proxy) | 延迟加载大型对象,如图片、视频加载 | 
| 安全代理(Protection Proxy) | 控制权限访问,如权限验证、安全审计 | 
| 智能代理(Smart Proxy) | 附加额外操作,如引用计数、日志记录等 | 
3. 结构角色
| 角色 | 职责说明 | 
|---|---|
| Subject | 抽象主题接口,定义目标行为 | 
| RealSubject | 真实对象,实现具体逻辑 | 
| Proxy | 代理对象,控制访问真实对象,可增强功能 | 
4. C++ 示例------访问图像的代理模式(虚拟代理)
抽象接口(Subject):
            
            
              cpp
              
              
            
          
          class Image {
public:
    virtual void display() = 0;
    virtual ~Image() = default;
};
        真实对象(RealSubject):
            
            
              cpp
              
              
            
          
          class RealImage : public Image {
private:
    std::string filename;
public:
    RealImage(const std::string& file) : filename(file) 
    {
        loadFromDisk();
    }
    void loadFromDisk() 
    {
        std::cout << "加载图片文件:" << filename << std::endl;
    }
    void display() override 
    {
        std::cout << "显示图片:" << filename << std::endl;
    }
};
        代理对象(Proxy):
            
            
              cpp
              
              
            
          
          class ProxyImage : public Image {
private:
    std::string filename;
    RealImage* realImage = nullptr;
public:
    ProxyImage(const std::string& file) : filename(file) {}
    void display() override 
    {
        if (!realImage) 
        {
            realImage = new RealImage(filename); // 延迟加载
        }
        realImage->display();
    }
    ~ProxyImage() 
    {
        delete realImage;
    }
};
        客户端使用:
            
            
              cpp
              
              
            
          
          int main() {
    Image* image = new ProxyImage("photo.jpg");
    std::cout << "第一次调用 display() :" << std::endl;
    image->display();  // 会加载 + 显示
    std::cout << "第二次调用 display() :" << std::endl;
    image->display();  // 直接显示,不再加载
    delete image;
    return 0;
}
        5. 优缺点分析
| 优点 | 缺点 | 
|---|---|
| 控制对象访问(权限、安全、远程调用) | 增加系统复杂度 | 
| 可延迟加载资源,提升性能(如虚拟代理) | 若过度使用,可能增加维护难度 | 
| 可增加额外功能(如日志、缓存、引用计数等) | 被代理对象接口变化时,代理类也需修改 | 
6. 实际应用
- 虚拟代理:大型图像延迟加载(如网页图片懒加载);
 - 安全代理:数据库连接权限控制;
 - 智能代理 :引用计数类(如智能指针 
std::shared_ptr); - 远程代理:RPC、gRPC 框架中的远程服务调用。
 
八、策略模式(Strategy Pattern)
1. 概念
策略模式 是一种典型的行为型设计模式,用于:
将一系列可互换的算法(或策略)封装起来,使它们可以独立于使用它们的客户端自由切换。
2. 适用场景
| 适用场景 | 示例 | 
|---|---|
| 存在多个算法/行为,可以灵活切换 | 支付方式(微信/支付宝)、排序算法选择等 | 
使用 if-else / switch 过多 | 
用策略类代替繁杂条件逻辑 | 
| 系统需要在运行时动态选择行为 | 游戏角色攻击方式、文件压缩算法(ZIP、RAR)等 | 
3. 结构组成
| 角色 | 职责说明 | 
|---|---|
| Strategy | 抽象策略类,定义算法接口 | 
| ConcreteStrategy | 具体策略类,实现不同算法或行为 | 
| Context | 上下文类,持有策略对象,供客户端使用 | 
4. C++ 示例------支付策略(微信、支付宝)
抽象策略类:
            
            
              cpp
              
              
            
          
          class PaymentStrategy {
public:
    virtual void pay(int amount) = 0;
    virtual ~PaymentStrategy() = default;
};
        具体策略类:
            
            
              cpp
              
              
            
          
          class WeChatPay : public PaymentStrategy {
public:
    void pay(int amount) override 
    {
        std::cout << "使用微信支付:" << amount << " 元" << std::endl;
    }
};
class Alipay : public PaymentStrategy {
public:
    void pay(int amount) override 
    {
        std::cout << "使用支付宝支付:" << amount << " 元" << std::endl;
    }
};
        上下文类(使用策略):
            
            
              cpp
              
              
            
          
          class PaymentContext {
private:
    PaymentStrategy* strategy;
public:
    PaymentContext(PaymentStrategy* strategy) : strategy(strategy) {}
    void setStrategy(PaymentStrategy* newStrategy) 
    {
        strategy = newStrategy;
    }
    void pay(int amount) 
    {
        strategy->pay(amount);
    }
};
        客户端使用示例:
            
            
              cpp
              
              
            
          
          int main() {
    WeChatPay wechat;
    Alipay alipay;
    PaymentContext context(&wechat);
    context.pay(100); // 使用微信支付
    context.setStrategy(&alipay);
    context.pay(200); // 使用支付宝支付
    return 0;
}
        5. 优缺点分析
| 优点 | 缺点 | 
|---|---|
| 算法可以自由切换,互不影响,符合开闭原则 | 客户端需要了解不同策略类以选择使用 | 
消除了大量 if-else,逻辑更清晰 | 
增加了类数量,每个策略都要写一个类 | 
| 可以在运行时动态选择策略,实现更灵活的行为扩展 | 若算法内部差异很小,会导致重复代码 | 
6. 现实应用
- 排序器中选择不同排序策略(快速排序、归并排序等);
 - 游戏中角色选择攻击行为(近战、远程、魔法);
 - 视频播放器根据网络状况切换清晰度策略。
 
九、装饰器模式(Decorator Pattern)
1. 概念
装饰器模式 (Decorator)是一种结构型设计模式,用于:
在不改变原始类代码 的前提下,动态地为对象添加额外的功能。
2. 使用场景
| 使用场景 | 示例 | 
|---|---|
| 动态添加/移除对象功能 | I/O 流(如 std::iostream) | 
| 避免子类爆炸式扩展(继承过多) | 代替多子类继承组合 | 
| 运行时灵活组合对象行为 | GUI 控件样式、文本处理管道等 | 
3. 结构角色
| 角色 | 职责说明 | 
|---|---|
| Component | 抽象接口,定义可以装饰的操作行为 | 
| ConcreteComponent | 具体对象,定义基本行为实现 | 
| Decorator | 抽象装饰器,包含一个 Component 成员 | 
| ConcreteDecorator | 实际装饰器,增加具体功能 | 
4. C++ 示例------饮料加调料系统
抽象组件接口(Component):
            
            
              cpp
              
              
            
          
          class Beverage {
public:
    virtual std::string getDescription() = 0;
    virtual double cost() = 0;
    virtual ~Beverage() = default;
};
        具体组件(ConcreteComponent):
            
            
              cpp
              
              
            
          
          class Coffee : public Beverage {
public:
    std::string getDescription() override 
    {
        return "Coffee";
    }
    double cost() override 
    {
        return 5.0;
    }
};
        抽象装饰器(Decorator):
            
            
              cpp
              
              
            
          
          class CondimentDecorator : public Beverage {
protected:
    Beverage* beverage;
public:
    CondimentDecorator(Beverage* b) : beverage(b) {}
};
        具体装饰器(ConcreteDecorator):
            
            
              cpp
              
              
            
          
          class Milk : public CondimentDecorator {
public:
    Milk(Beverage* b) : CondimentDecorator(b) {}
    std::string getDescription() override 
    {
        return beverage->getDescription() + ", Milk";
    }
    double cost() override 
    {
        return beverage->cost() + 1.5;
    }
};
class Sugar : public CondimentDecorator {
public:
    Sugar(Beverage* b) : CondimentDecorator(b) {}
    std::string getDescription() override 
    {
        return beverage->getDescription() + ", Sugar";
    }
    double cost() override 
    {
        return beverage->cost() + 0.5;
    }
};
        客户端使用:
            
            
              cpp
              
              
            
          
          int main() {
    Beverage* beverage = new Coffee();                  // 基础咖啡
    beverage = new Milk(beverage);                     // 加牛奶
    beverage = new Sugar(beverage);                    // 加糖
    std::cout << "饮料描述: " << beverage->getDescription() << std::endl;
    std::cout << "总价: " << beverage->cost() << " 元" << std::endl;
    delete beverage; // 实际应逐层释放
    return 0;
}
        5. 优缺点分析
| 优点 | 缺点 | 
|---|---|
| 不改变原始类,实现"开闭原则" | 类数目可能增多 | 
| 支持功能组合,灵活拓展 | 多层嵌套可能导致调试困难 | 
| 替代继承层级,避免子类爆炸式增长 | 对象创建较多(每层一个) | 
6. 现实应用
- Java I/O 流 (
BufferedInputStream,DataInputStream等); - 图形组件样式叠加(边框、阴影、背景);
 - 日志增强、权限控制模块;
 - C++ 中的流操作符 (如 
std::ostream装饰行为), 
十、常用设计模式的比较
| 模式名称 | 目的 | 典型应用场景 | 优点 | 缺点 | 
|---|---|---|---|---|
| 单例模式 | 保证一个类只有一个实例,并提供全局访问点 | 配置管理器、线程池、数据库连接池、日志管理器 | 控制实例数量、节省资源、提供全局访问点 | 不易扩展、对测试不友好、多线程需加锁维护单例安全 | 
| 工厂模式 | 将对象的创建过程封装起来,客户端无需了解对象创建的具体细节 | 创建复杂对象、大量具有共性但不完全相同的对象 | 解耦创建和使用,增强扩展性和灵活性 | 增加系统复杂性,类数量增多 | 
| 观察者模式 | 建立一对多的依赖关系,一旦主题对象状态变化,所有观察者都会收到通知 | 消息订阅系统、事件驱动模型、GUI 事件处理、MVC 模式 | 实现解耦,支持广播通信,符合开闭原则 | 可能引发性能问题或通知混乱,观察者之间存在隐式依赖 | 
| 策略模式 | 将算法封装为独立的策略类,使其可以互换,以便在运行时选择不同的行为 | 算法族(如排序、压缩)、游戏 AI 策略、支付方式选择 | 策略独立、便于切换、符合开闭原则 | 增加类数量,客户端必须了解不同策略的作用 | 
| 代理模式 | 通过代理对象控制对目标对象的访问,可添加额外控制逻辑(如权限、懒加载等) | 安全控制、延迟加载、远程调用、对象池、日志记录 | 控制对象访问、增强原对象功能、不改变原有类 | 增加系统复杂性,可能引入性能开销 | 
| 装饰器模式 | 动态地为对象添加额外职责,不修改其结构,实现行为扩展 | IO流处理、图形组件增强、权限验证、日志记录、缓存处理 | 比继承更灵活,职责细化、符合开闭原则 | 多层装饰可能导致调试困难,创建大量装饰类 | 
使用建议:
- 要 控制对象数量 → 单例模式;
 - 要 封装对象创建逻辑 → 工厂模式;
 - 要 对象间解耦并实时通知 → 观察者模式;
 - 要 算法/行为灵活切换 → 策略模式;
 - 要 控制对象访问/增强功能 → 代理模式;
 - 要 在不改变原对象的基础上扩展功能 → 装饰器模式。