计算机基础(一)——设计模式

一、设计模式

设计模式(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流处理、图形组件增强、权限验证、日志记录、缓存处理 比继承更灵活,职责细化、符合开闭原则 多层装饰可能导致调试困难,创建大量装饰类

使用建议:

  • 控制对象数量 → 单例模式;
  • 封装对象创建逻辑 → 工厂模式;
  • 对象间解耦并实时通知 → 观察者模式;
  • 算法/行为灵活切换 → 策略模式;
  • 控制对象访问/增强功能 → 代理模式;
  • 在不改变原对象的基础上扩展功能 → 装饰器模式。
相关推荐
mxpan1 小时前
C++ 单例模式一种实现方式
c++·设计模式
全栈小51 小时前
【数据库】在线体验KingbaseES平台,零门槛学习,并快速体验Oracle增改查全基础功能
数据库·学习·oracle
来两个炸鸡腿1 小时前
【Datawhale组队学习202506】YOLO-Master task02 YOLO系列发展线
python·深度学习·学习·yolo
only-lucky2 小时前
C++设计模式
java·c++·设计模式
勤奋的知更鸟2 小时前
Java 编程之代理模式
java·开发语言·设计模式·代理模式
蔡蓝3 小时前
设计模式-桥接模式
java·设计模式·桥接模式
我崽不熬夜4 小时前
为什么Java中的设计模式会让你的代码更优雅?
java·后端·设计模式
xwz小王子4 小时前
Science Robotics期刊论文:腿式机械臂学习羽毛球技能
学习·羽毛球
唐人编唐码5 小时前
产品经理如何快速理解设计模式
设计模式·产品经理