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

一、设计模式

设计模式(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++ 中的经典实现(线程安全 + 懒汉式)

#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),由对应的工厂类生成。

产品抽象类:

class Shape {
public:
    virtual void draw() = 0; // 纯虚函数
    virtual ~Shape() = default;
};

具体产品类:

class Circle : public Shape {
public:
    void draw() override 
    {
        std::cout << "绘制圆形" << std::endl;
    }
};

class Rectangle : public Shape {
public:
    void draw() override 
    {
        std::cout << "绘制矩形" << std::endl;
    }
};

工厂抽象类:

class ShapeFactory {
public:
    virtual Shape* createShape() = 0; // 创建产品接口
    virtual ~ShapeFactory() = default;
};

具体工厂类:

class CircleFactory : public ShapeFactory {
public:
    Shape* createShape() override 
    {
        return new Circle();
    }
};

class RectangleFactory : public ShapeFactory {
public:
    Shape* createShape() override 
    {
        return new Rectangle();
    }
};

客户端使用:

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)数据变化,通知多个显示设备(观察者)。

抽象观察者接口:

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

主题(Subject)接口:

#include <vector>

class Subject {
public:
    virtual void attach(Observer* observer) = 0;
    virtual void detach(Observer* observer) = 0;
    virtual void notify() = 0;
    virtual ~Subject() = default;
};

具体主题类:

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);
        }
    }
};

具体观察者类:

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;
    }
};

客户端使用:

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):

class Image {
public:
    virtual void display() = 0;
    virtual ~Image() = default;
};

真实对象(RealSubject):

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):

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;
    }
};

客户端使用:

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++ 示例——支付策略(微信、支付宝)

抽象策略类:

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

具体策略类:

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;
    }
};

上下文类(使用策略):

class PaymentContext {
private:
    PaymentStrategy* strategy;

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

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

    void pay(int amount) 
    {
        strategy->pay(amount);
    }
};

客户端使用示例:

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):

class Beverage {
public:
    virtual std::string getDescription() = 0;
    virtual double cost() = 0;
    virtual ~Beverage() = default;
};

具体组件(ConcreteComponent):

class Coffee : public Beverage {
public:
    std::string getDescription() override 
    {
        return "Coffee";
    }

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

抽象装饰器(Decorator):

class CondimentDecorator : public Beverage {
protected:
    Beverage* beverage;
public:
    CondimentDecorator(Beverage* b) : beverage(b) {}
};

具体装饰器(ConcreteDecorator):

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;
    }
};

客户端使用:

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

使用建议:

  • 控制对象数量 → 单例模式;
  • 封装对象创建逻辑 → 工厂模式;
  • 对象间解耦并实时通知 → 观察者模式;
  • 算法/行为灵活切换 → 策略模式;
  • 控制对象访问/增强功能 → 代理模式;
  • 在不改变原对象的基础上扩展功能 → 装饰器模式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奕天者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值