本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:设计模式是软件工程中的核心概念,代表在特定场景下解决常见问题的最佳实践与可复用方案。本套C++设计模式PPT深入讲解了设计模式的基本原理与在C++语言中的具体实现方式,适合初学者系统学习。内容涵盖创建型、结构型和行为型三大类模式,通过实例代码帮助理解如何在实际开发中应用这些模式,提升代码的可读性、可维护性与可扩展性。同时强调设计模式的合理使用,避免过度依赖,结合C++特性实现高质量软件架构。
设计模式ppt(C++)

1. 设计模式基本概念

设计模式是软件工程中经过验证的、用于解决特定场景下设计问题的模板化解决方案。它并非代码,而是一种描述在特定上下文中如何组织类与对象以达到良好设计的方法论。

1.1 设计模式的定义与分类

设计模式(Design Pattern)是指在软件设计过程中反复出现的问题及其标准化的解决方案。它包含四要素: 模式名称 (Pattern Name)用于标识模式, 问题 (Problem)描述适用场景, 解决方案 (Solution)是类与对象的结构化组织方式, 效果 (Consequences)则体现该方案的优缺点和权衡点。

根据其目的和应用场景,设计模式主要分为三大类:

类型 描述 常见模式示例
创建型模式 负责对象的创建与初始化,封装对象创建的复杂性 单例、工厂、建造者、原型等
结构型模式 关注对象与类之间的组合方式,优化系统结构 适配器、装饰器、代理、组合等
行为型模式 描述对象之间的交互与职责分配 观察者、策略、模板方法、命令等

设计模式的引入提升了代码的可维护性、可扩展性和可复用性,是面向对象设计的重要组成部分。

2. 创建型模式介绍与实现

创建型模式(Creational Patterns)是设计模式中最基础的一类,其核心目标是将对象的 创建逻辑 从其 使用逻辑 中分离出来,从而提升系统的灵活性、可维护性和可扩展性。这类模式不仅解决了对象如何被创建的问题,还通过封装对象创建的复杂性,使得系统对具体类的依赖减少,增强了模块之间的解耦能力。

本章将深入探讨五种常见的创建型模式: 单例模式 (Singleton)、 工厂模式 (Factory)、 建造者模式 (Builder)、 原型模式 (Prototype)以及 抽象工厂模式 (Abstract Factory)。我们将以C++语言为基础,详细分析每种模式的原理、结构和实现方式,并结合实际代码进行说明,帮助读者掌握其在实际开发中的应用。

2.1 创建型模式概述

创建型模式的核心思想是 将对象的创建与使用分离 ,使得系统在对象的创建过程中具备更高的灵活性和扩展性。这一类模式通常关注如何构造和组合对象,以适应不断变化的需求。

2.1.1 创建型模式的基本思想

创建型模式的基本思想可以归纳为以下几点:

  • 封装对象的创建逻辑 :隐藏对象创建的具体细节,避免创建过程对调用者造成干扰。
  • 提高系统的可扩展性 :当需要新增对象类型时,不需要修改已有代码,只需要扩展新的创建逻辑。
  • 支持多态性 :通过接口或抽象类返回具体对象,使得调用者无需关心具体实现类。

创建型模式通常通过引入 工厂类 建造者类 克隆机制 等方式,将对象的创建逻辑从客户端代码中抽离出来,从而实现对象创建的统一管理和灵活配置。

2.1.2 创建对象与系统解耦的重要性

在软件开发中,对象之间的依赖关系是不可避免的。然而,如果一个类直接通过 new 关键字创建另一个类的实例,那么它就与该类产生了强耦合。一旦该类发生变化,调用者也需要进行相应的修改。

通过使用创建型模式,我们可以将这种耦合关系降到最低。例如,使用工厂模式时,客户端只需要知道接口或抽象类,而具体的实现类则由工厂负责创建。这种设计方式不仅提升了系统的可维护性,也便于进行单元测试和模块替换。

2.2 单例模式详解与C++实现

单例模式(Singleton Pattern)是一种确保一个类只有一个实例,并提供一个全局访问点的设计模式。它广泛应用于资源管理、日志记录、数据库连接等场景中。

2.2.1 单例模式的基本原理与适用场景

基本原理

单例模式的核心在于:

  • 私有化构造函数,防止外部创建实例。
  • 提供一个静态方法或属性,返回该类的唯一实例。
  • 控制实例的创建过程,确保只创建一次。
适用场景
  • 当系统中需要一个全局唯一的对象时,如配置管理器、线程池、缓存等。
  • 当对象创建代价较高时,如数据库连接、网络资源等。
  • 当多个对象之间需要共享状态或资源时。
优点
  • 提供全局访问点,简化对象的获取方式。
  • 避免重复创建对象,节省系统资源。
  • 控制对象的生命周期,便于统一管理。
缺点
  • 单例对象在程序生命周期内始终存在,可能导致资源浪费。
  • 在多线程环境下,需要特别注意线程安全问题。
  • 单例对象的生命周期难以控制,可能影响系统的可测试性和可维护性。

2.2.2 C++中线程安全单例的实现方式

在多线程环境中,传统的懒汉式单例可能在多个线程同时调用获取实例方法时导致多个实例被创建。为了解决这个问题,我们可以使用 双重检查锁定 (Double-Checked Locking)来实现线程安全的单例。

示例代码
#include <iostream>
#include <mutex>

class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx;

    Singleton() { std::cout << "Singleton created." << std::endl; }

public:
    static Singleton* getInstance() {
        if (instance == nullptr) {
            std::lock_guard<std::mutex> lock(mtx);
            if (instance == nullptr) {
                instance = new Singleton();
            }
        }
        return instance;
    }

    void doSomething() {
        std::cout << "Singleton is doing something." << std::endl;
    }
};

// 初始化静态成员
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

int main() {
    Singleton* s1 = Singleton::getInstance();
    Singleton* s2 = Singleton::getInstance();

    if (s1 == s2) {
        std::cout << "Same instance!" << std::endl;
    }

    s1->doSomething();
    return 0;
}
代码分析
  • 私有构造函数 :防止外部直接通过 new 创建实例。
  • 双重检查机制 :第一次检查 instance == nullptr 是为了避免不必要的加锁,第二次检查是为了确保在加锁后仍然只有一个实例。
  • std::mutex :用于保证多线程下的线程安全。
  • std::lock_guard :自动加锁和解锁,防止死锁。
  • 静态成员变量 :保存唯一的实例。
优化建议
  • 使用C++11的 std::call_once std::once_flag 实现更简洁的线程安全单例。
  • 使用局部静态变量(Meyer’s Singleton)方式实现线程安全且更简洁的单例:
static Singleton& getInstance() {
    static Singleton instance;
    return instance;
}

这种方式由C++11标准保证线程安全,无需手动加锁,是目前最推荐的方式。

2.3 工厂模式详解与C++实现

工厂模式(Factory Pattern)是一种通过 工厂类 统一管理对象创建过程的设计模式。它将对象的创建逻辑封装在工厂类中,客户端只需通过工厂接口获取所需对象,而不必关心具体实现类。

2.3.1 简单工厂、工厂方法与抽象工厂的区别

模式名称 说明 适用场景
简单工厂 一个工厂类根据参数决定创建哪种对象,违反开闭原则 对象种类少、变化不频繁的场景
工厂方法 定义一个用于创建对象的接口,让子类决定实例化哪一个类 需要子类扩展的场景
抽象工厂 提供一个创建一系列相关或相互依赖对象的家族接口 创建一组相关对象,如跨平台组件

2.3.2 工厂模式在C++中的类结构设计与代码实现

类图(使用Mermaid)
classDiagram
    class Factory {
        +createProduct() : Product*
    }

    class Product {
        +use()
    }

    class ConcreteProductA {
        +use()
    }

    class ConcreteProductB {
        +use()
    }

    Factory --> Product : 创建
    Product <|-- ConcreteProductA
    Product <|-- ConcreteProductB
示例代码
#include <iostream>

class Product {
public:
    virtual void use() = 0;
    virtual ~Product() {}
};

class ConcreteProductA : public Product {
public:
    void use() override {
        std::cout << "Using Product A" << std::endl;
    }
};

class ConcreteProductB : public Product {
public:
    void use() override {
        std::cout << "Using Product B" << std::endl;
    }
};

class Factory {
public:
    Product* createProduct(const std::string& type) {
        if (type == "A") {
            return new ConcreteProductA();
        } else if (type == "B") {
            return new ConcreteProductB();
        }
        return nullptr;
    }
};

int main() {
    Factory factory;
    Product* productA = factory.createProduct("A");
    Product* productB = factory.createProduct("B");

    productA->use();  // 输出:Using Product A
    productB->use();  // 输出:Using Product B

    delete productA;
    delete productB;
    return 0;
}
代码分析
  • 抽象类Product :定义产品的公共接口。
  • 具体产品类 :实现具体的业务逻辑。
  • 工厂类Factory :根据传入的字符串参数创建不同的产品实例。
  • 客户端代码 :无需知道具体产品类,只需通过工厂接口获取对象。
优化建议
  • 使用智能指针(如 std::unique_ptr )代替原始指针,避免内存泄漏。
  • 使用 工厂方法模式 ,将工厂类抽象化,支持多态创建。
  • 使用 抽象工厂模式 来创建一组相关的产品族,增强扩展性。

2.4 建造者模式详解与C++实现

建造者模式(Builder Pattern)用于构建复杂对象,它将一个对象的构建过程与其表示分离,使得相同的构建过程可以创建不同的表示。

2.4.1 建造者模式的结构与流程

建造者模式主要包含以下几个角色:

  • Builder :抽象接口,定义创建产品各个部分的方法。
  • ConcreteBuilder :具体构建者,实现接口,构造和装配各个部件。
  • Director :指挥者,负责调用Builder的方法来构建产品。
  • Product :被构建的复杂对象。
类图(使用Mermaid)
classDiagram
    class Director {
        +construct()
    }

    class Builder {
        +buildPartA()
        +buildPartB()
        +getResult()
    }

    class ConcreteBuilder {
        +buildPartA()
        +buildPartB()
        +getResult()
    }

    class Product {
        +show()
    }

    Director --> Builder
    Builder <|-- ConcreteBuilder
    ConcreteBuilder --> Product

2.4.2 使用C++实现复杂对象的构建过程

示例代码
#include <iostream>
#include <string>

class Product {
private:
    std::string partA;
    std::string partB;

public:
    void setPartA(const std::string& a) { partA = a; }
    void setPartB(const std::string& b) { partB = b; }

    void show() {
        std::cout << "PartA: " << partA << ", PartB: " << partB << std::endl;
    }
};

class Builder {
public:
    virtual void buildPartA() = 0;
    virtual void buildPartB() = 0;
    virtual Product getResult() = 0;
};

class ConcreteBuilder : public Builder {
private:
    Product product;

public:
    void buildPartA() override {
        product.setPartA("PartA Built");
    }

    void buildPartB() override {
        product.setPartB("PartB Built");
    }

    Product getResult() override {
        return product;
    }
};

class Director {
private:
    Builder* builder;

public:
    void setBuilder(Builder* b) { builder = b; }

    void construct() {
        builder->buildPartA();
        builder->buildPartB();
    }
};

int main() {
    ConcreteBuilder builder;
    Director director;

    director.setBuilder(&builder);
    director.construct();

    Product product = builder.getResult();
    product.show();  // 输出:PartA: PartA Built, PartB: PartB Built

    return 0;
}
代码分析
  • Builder接口 :定义了构建产品各个部分的方法。
  • ConcreteBuilder实现类 :具体构建逻辑。
  • Director指挥者 :控制构建流程。
  • Product对象 :最终构建的复杂对象。
优化建议
  • 使用模板方法模式优化Director类,使其更通用。
  • 使用链式调用简化Builder的构建过程。
  • 支持多种构建方式,如JSON、XML等配置文件驱动构建。

2.5 原型模式详解与C++实现

原型模式(Prototype Pattern)是一种通过克隆已有对象来创建新对象的设计模式。它适用于对象创建成本较高,或者对象的创建过程较为复杂的情况。

2.5.1 原型模式的核心思想与深拷贝实现

原型模式的核心在于 通过复制现有对象来创建新对象 ,而不是通过构造函数。这可以避免重复执行复杂的初始化逻辑。

在C++中,原型模式通常通过实现 clone() 方法,并重载拷贝构造函数或使用 std::unique_ptr 来实现深拷贝。

示例代码
#include <iostream>
#include <memory>

class Prototype {
public:
    virtual std::unique_ptr<Prototype> clone() const = 0;
    virtual void show() const = 0;
    virtual ~Prototype() {}
};

class ConcretePrototype : public Prototype {
private:
    int value;

public:
    ConcretePrototype(int v) : value(v) {}

    std::unique_ptr<Prototype> clone() const override {
        return std::make_unique<ConcretePrototype>(*this);
    }

    void show() const override {
        std::cout << "Value: " << value << std::endl;
    }
};

int main() {
    ConcretePrototype p1(10);
    auto p2 = p1.clone();

    p1.show();  // 输出:Value: 10
    p2->show(); // 输出:Value: 10

    return 0;
}
代码分析
  • Prototype抽象类 :定义 clone() show() 接口。
  • ConcretePrototype具体类 :实现克隆逻辑。
  • std::unique_ptr :自动管理内存,避免泄漏。
  • clone()方法 :返回当前对象的深拷贝。

2.5.2 在C++中通过克隆创建对象的实践

  • 深拷贝 vs 浅拷贝 :原型模式强调深拷贝,确保克隆对象与原对象互不影响。
  • 可扩展性 :可以通过继承扩展新的原型类,而无需修改已有代码。
  • 适用场景 :适合对象创建成本高、初始化复杂或需动态变化的场景。
优化建议
  • 使用智能指针(如 std::shared_ptr )支持多对象共享。
  • 使用注册机制实现原型工厂,支持运行时动态添加原型对象。

(未完待续)

3. 结构型模式介绍与实现

结构型模式是设计模式中的第二大类别,主要关注对象与对象之间的组合方式,解决对象之间如何高效、灵活地协作的问题。结构型模式通过组合对象来创建更复杂的结构,帮助开发者构建可扩展、易维护的系统架构。在C++中,结构型模式常用于解决对象之间的依赖关系、接口兼容性问题、以及组件之间的松耦合需求。

本章将系统性地介绍结构型模式的分类与核心思想,并结合C++语言实现适配器模式、装饰器模式以及组合模式与代理模式的应用,帮助开发者理解其设计原理与实际用途。

3.1 结构型模式概述

结构型模式的核心在于“结构”二字,它关注的是对象与对象之间的关系构建方式。这些模式帮助开发者在不破坏系统稳定性的前提下,灵活地组织对象,实现良好的可扩展性和可维护性。

3.1.1 结构型模式解决的问题类型

结构型模式通常用于解决以下几类问题:

问题类型 典型模式 描述
接口不兼容 适配器模式(Adapter) 将一个类的接口转换为客户希望的另一个接口
动态添加功能 装饰器模式(Decorator) 动态地给对象添加职责,比继承更灵活
对象组合 组合模式(Composite) 将对象组合成树形结构以表示“部分-整体”的层次结构
代理访问 代理模式(Proxy) 控制对象的访问,延迟加载、权限控制等
对象共享 享元模式(Flyweight) 使用共享技术来支持大量细粒度的对象
对象结构操作 外观模式(Facade) 提供一个统一的接口,简化子系统的使用
类型组合 桥接模式(Bridge) 将抽象部分与其实现部分分离,使它们可以独立变化

这些模式共同的特点是通过对象之间的结构关系,提升系统的灵活性和可扩展性。

3.1.2 对象与对象之间的组合方式

结构型模式的本质在于对象之间的组合。这种组合可以分为两种形式:

  • 静态组合 :编译期就确定对象之间的关系,例如继承。
  • 动态组合 :运行时动态构建对象之间的关系,例如装饰器、适配器等。

在面向对象系统中,动态组合更具有灵活性,它允许在不修改已有代码的前提下,通过组合的方式实现新的行为。

例如,使用装饰器模式可以动态地为对象添加功能,而不必通过继承生成大量子类:

class TextMessage {
public:
    virtual void send(const std::string& content) {
        std::cout << "Send message: " << content << std::endl;
    }
};

class EncryptedMessage : public TextMessage {
    TextMessage* message;
public:
    EncryptedMessage(TextMessage* msg) : message(msg) {}
    void send(const std::string& content) override {
        std::string encrypted = encrypt(content);
        message->send(encrypted);
    }
private:
    std::string encrypt(const std::string& content) {
        // 模拟加密过程
        return "encrypted_" + content;
    }
};

代码逻辑分析:

  • TextMessage 是基础类,定义了发送消息的基本行为。
  • EncryptedMessage 是装饰器类,它包裹了原始的 TextMessage 实例,并在其发送逻辑前添加加密操作。
  • 通过构造函数传入原始对象,实现装饰器对原始行为的增强。
  • encrypt 方法模拟加密逻辑,返回加密后的字符串。
  • 该模式允许在运行时动态地组合多个装饰器,如压缩、日志记录等,而不影响原有类结构。

参数说明:

  • message :被装饰的对象,允许在运行时传入不同的实现。
  • content :待发送的消息内容,经过装饰器处理后可附加额外行为。

这种组合方式体现了结构型模式的精髓: 通过对象的组合而非继承,实现灵活的系统扩展。

3.2 适配器模式详解与C++实现

适配器模式用于解决接口不兼容的问题,使得原本由于接口不匹配而无法一起工作的类能够协同工作。

3.2.1 类适配器与对象适配器的实现差异

适配器模式有两种实现方式:

实现方式 特点 适用场景
类适配器 使用多重继承实现 适用于C++等支持多重继承的语言
对象适配器 使用组合方式实现 更通用,适用于所有面向对象语言

类适配器示例:

class Target {
public:
    virtual void request() {
        std::cout << "Target::request" << std::endl;
    }
};

class Adaptee {
public:
    void specificRequest() {
        std::cout << "Adaptee::specificRequest" << std::endl;
    }
};

class ClassAdapter : public Target, private Adaptee {
public:
    void request() override {
        specificRequest();
    }
};

对象适配器示例:

class ObjectAdapter : public Target {
    Adaptee* adaptee;
public:
    ObjectAdapter(Adaptee* a) : adaptee(a) {}
    void request() override {
        adaptee->specificRequest();
    }
};

逻辑分析:

  • 类适配器通过继承 Target Adaptee 实现接口转换。
  • 对象适配器通过组合方式持有 Adaptee 实例,调用其方法完成适配。
  • 类适配器更简洁,但受限于语言是否支持多重继承。
  • 对象适配器更通用,适用于大多数现代面向对象语言。

3.2.2 使用C++实现接口兼容的适配逻辑

适配器模式在实际项目中应用广泛,比如:

  • 旧系统接口与新系统集成
  • 第三方库接口与项目代码的适配
  • 不同平台下的接口统一

下面是一个实际案例:假设我们有一个日志系统,支持 LogSystem 接口,但需要接入一个第三方日志库 ThirdPartyLogger ,其接口不兼容:

class LogSystem {
public:
    virtual void log(const std::string& message) = 0;
};

class ThirdPartyLogger {
public:
    void writeLog(const std::string& level, const std::string& content) {
        std::cout << "[" << level << "] " << content << std::endl;
    }
};

class LoggerAdapter : public LogSystem, private ThirdPartyLogger {
public:
    void log(const std::string& message) override {
        writeLog("INFO", message);
    }
};

参数说明:

  • writeLog 是第三方库的方法,接受日志级别和内容。
  • log 是目标接口方法,适配器将其转换为调用第三方方法,并添加默认级别。

使用方式:

int main() {
    LogSystem* logger = new LoggerAdapter();
    logger->log("User login successful.");
    return 0;
}

输出结果:

[INFO] User login successful.

mermaid流程图:

classDiagram
    class LogSystem {
        <<interface>>
        +log(message: string)
    }

    class LoggerAdapter {
        +log(message: string)
    }

    class ThirdPartyLogger {
        +writeLog(level: string, content: string)
    }

    LogSystem <|-- LoggerAdapter
    LoggerAdapter --> ThirdPartyLogger

3.3 装饰器模式详解与C++实现

装饰器模式用于在不改变原有对象结构的前提下,动态地添加功能。它比继承更灵活,适合需要组合多种功能的场景。

3.3.1 装饰器模式与继承的区别

对比维度 继承 装饰器
扩展方式 静态 动态
组合方式 类继承 对象组合
灵活性 有限
适用性 固定结构 多种组合场景

装饰器通过组合方式动态增强对象功能,避免了类爆炸的问题。

3.3.2 在C++中实现运行时功能扩展

下面是一个装饰器模式的完整示例,展示如何为文本消息添加压缩、加密、签名等功能:

class Message {
public:
    virtual void send(const std::string& content) = 0;
};

class PlainMessage : public Message {
public:
    void send(const std::string& content) override {
        std::cout << "Send: " << content << std::endl;
    }
};

class CompressedMessage : public Message {
    Message* message;
public:
    CompressedMessage(Message* msg) : message(msg) {}
    void send(const std::string& content) override {
        std::string compressed = compress(content);
        message->send(compressed);
    }
private:
    std::string compress(const std::string& str) {
        return "compressed_" + str;
    }
};

class EncryptedMessage : public Message {
    Message* message;
public:
    EncryptedMessage(Message* msg) : message(msg) {}
    void send(const std::string& content) override {
        std::string encrypted = encrypt(content);
        message->send(encrypted);
    }
private:
    std::string encrypt(const std::string& str) {
        return "encrypted_" + str;
    }
};

使用方式:

int main() {
    Message* msg = new PlainMessage();
    msg = new EncryptedMessage(msg);
    msg = new CompressedMessage(msg);
    msg->send("Secret data");
    return 0;
}

输出结果:

Send: compressed_encrypted_Secret data

参数说明:

  • message :被装饰的消息对象,允许在运行时动态组合。
  • compress encrypt :模拟压缩和加密逻辑,返回处理后的字符串。

mermaid流程图:

classDiagram
    class Message {
        <<interface>>
        +send(content: string)
    }

    class PlainMessage {
        +send(content: string)
    }

    class CompressedMessage {
        +send(content: string)
    }

    class EncryptedMessage {
        +send(content: string)
    }

    Message <|-- PlainMessage
    Message <|-- CompressedMessage
    Message <|-- EncryptedMessage

    CompressedMessage --> Message
    EncryptedMessage --> Message

3.4 组合模式与代理模式简介

组合模式与代理模式是结构型模式中两个重要的成员,分别用于构建树形结构和控制对象访问。

3.4.1 组合模式的树形结构构建

组合模式允许将对象组合成树形结构,表示“部分-整体”的层次结构。适用于文件系统、UI组件、菜单等具有嵌套结构的场景。

class Component {
public:
    virtual void operation() = 0;
    virtual void add(Component*) {}
    virtual void remove(Component*) {}
    virtual Component* getChild(int) { return nullptr; }
};

class Leaf : public Component {
public:
    void operation() override {
        std::cout << "Leaf operation" << std::endl;
    }
};

class Composite : public Component {
    std::vector<Component*> children;
public:
    void add(Component* c) override {
        children.push_back(c);
    }
    void remove(Component* c) override {
        children.erase(std::remove(children.begin(), children.end(), c), children.end());
    }
    Component* getChild(int index) override {
        return children[index];
    }
    void operation() override {
        for (auto child : children) {
            child->operation();
        }
    }
};

使用方式:

int main() {
    Composite root;
    root.add(new Leaf());
    Composite sub;
    sub.add(new Leaf());
    root.add(&sub);
    root.operation();
    return 0;
}

输出结果:

Leaf operation
Leaf operation

mermaid流程图:

graph TD
    A[Composite] --> B[Leaf]
    A --> C[Composite]
    C --> D[Leaf]

3.4.2 代理模式的远程、虚拟和保护代理实现

代理模式用于控制对象的访问,常见的有:

  • 远程代理 :代表一个远程对象,如网络服务调用。
  • 虚拟代理 :延迟加载资源,如图片加载。
  • 保护代理 :控制访问权限。

虚拟代理示例:

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

class RealImage : public Image {
    std::string filename;
public:
    RealImage(const std::string& name) : filename(name) {}
    void display() override {
        std::cout << "Displaying image: " << filename << std::endl;
    }
};

class ProxyImage : public Image {
    std::string filename;
    RealImage* realImage;
public:
    ProxyImage(const std::string& name) : filename(name), realImage(nullptr) {}
    void display() override {
        if (!realImage) {
            realImage = new RealImage(filename);
        }
        realImage->display();
    }
};

使用方式:

int main() {
    Image* image = new ProxyImage("photo.jpg");
    image->display();  // 第一次调用,加载图片
    image->display();  // 已加载,直接显示
    return 0;
}

输出结果:

Displaying image: photo.jpg
Displaying image: photo.jpg

mermaid流程图:

classDiagram
    class Image {
        <<interface>>
        +display()
    }

    class RealImage {
        +display()
    }

    class ProxyImage {
        +display()
    }

    Image <|-- RealImage
    Image <|-- ProxyImage
    ProxyImage --> RealImage

4. 行为型模式介绍与实现

行为型模式主要关注对象之间的交互和职责分配,它解决了对象之间通信和协作的问题。这些模式通常用于提高系统的灵活性、可维护性和可扩展性。本章将深入探讨观察者模式、策略模式以及模板方法模式,结合C++语言实现,展示这些行为型模式如何在实际开发中发挥作用。

4.1 行为型模式概述

行为型模式是设计模式中的一个重要类别,专注于对象之间的交互方式和职责划分。它们通常用于封装变化,解耦对象之间的依赖关系,使得系统更加灵活、易于维护和扩展。

4.1.1 行为型模式关注对象间的交互

行为型模式的核心在于对象之间的协作。它们通常涉及对象之间的通信机制、事件通知机制、策略切换机制等。这些模式帮助开发者设计出松耦合的系统结构,使得组件之间可以独立变化而不影响整体系统。

例如:

  • 观察者模式 :定义对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都会收到通知。
  • 策略模式 :允许在运行时动态改变对象的行为,通过封装不同的算法或策略来实现行为的多样性。
  • 模板方法模式 :定义一个算法的骨架,而将一些步骤延迟到子类中实现,使得子类可以在不改变算法结构的前提下重新定义某些步骤。

这些模式通过封装对象之间的交互逻辑,使得系统的各个部分可以独立演化,提高了代码的复用性和可维护性。

4.1.2 行为型模式的常见分类与应用场景

行为型模式包括但不限于以下几种:

模式名称 应用场景描述
观察者模式 用于实现事件驱动系统,如UI组件更新、消息通知等
策略模式 用于在运行时切换不同的算法或行为,如支付方式切换、排序策略切换等
模板方法模式 用于定义算法的骨架,子类可以重写特定步骤,如数据库操作模板、流程引擎等
命令模式 用于实现请求的封装、队列、日志记录等
责任链模式 用于请求的处理流程中多个对象的协作,如审批流程、过滤器链等
状态模式 用于对象状态变化时行为的变化,如订单状态切换、游戏角色状态管理等
访问者模式 用于对对象结构进行操作,而无需修改对象结构本身
中介者模式 用于简化对象之间的通信,避免对象之间形成复杂的依赖关系
解释器模式 用于构建特定语言的解析器,如正则表达式解析、配置文件解析等

这些模式广泛应用于各种系统中,尤其是在需要灵活处理对象交互、动态行为切换、流程控制等场景下。理解这些模式的应用背景和实现原理,有助于我们在实际开发中更好地设计和优化系统结构。

4.2 观察者模式详解与C++实现

观察者模式是一种对象行为型模式,用于定义对象间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会自动收到通知并更新。该模式常用于实现事件驱动机制,如用户界面更新、消息广播等。

4.2.1 观察者与被观察者的依赖关系

观察者模式包含两个核心角色:

  • Subject(主题/被观察者) :负责维护观察者列表,并在状态变化时通知所有观察者。
  • Observer(观察者) :接收主题的通知,并作出相应的更新。

它们之间的关系如下图所示:

classDiagram
    class Subject {
        +registerObserver(Observer)
        +removeObserver(Observer)
        +notifyObservers()
    }
    class Observer {
        +update()
    }
    Subject <|-- ConcreteSubject
    Observer <|-- ConcreteObserver
    ConcreteSubject --> "1..*" ConcreteObserver

如上图所示, ConcreteSubject 是具体的主题类,维护一个观察者列表,并在状态变化时调用 notifyObservers() 方法通知所有观察者。 ConcreteObserver 是具体的观察者类,实现 update() 方法以响应通知。

4.2.2 使用C++实现事件通知机制

下面是一个使用C++实现的观察者模式示例,演示如何通过观察者模式实现一个简单的事件通知系统。

#include <iostream>
#include <vector>
#include <algorithm>

// 抽象观察者类
class Observer {
public:
    virtual void update(int value) = 0;
};

// 抽象主题类
class Subject {
public:
    virtual void registerObserver(Observer* observer) = 0;
    virtual void removeObserver(Observer* observer) = 0;
    virtual void notifyObservers() = 0;
};

// 具体主题类
class ConcreteSubject : public Subject {
private:
    std::vector<Observer*> observers;
    int value;

public:
    void registerObserver(Observer* observer) override {
        observers.push_back(observer);
    }

    void removeObserver(Observer* observer) override {
        observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
    }

    void notifyObservers() override {
        for (Observer* observer : observers) {
            observer->update(value);
        }
    }

    void setValue(int newValue) {
        value = newValue;
        notifyObservers(); // 状态变化时通知所有观察者
    }
};

// 具体观察者类A
class ConcreteObserverA : public Observer {
public:
    void update(int value) override {
        std::cout << "ConcreteObserverA: Received update with value " << value << std::endl;
    }
};

// 具体观察者类B
class ConcreteObserverB : public Observer {
public:
    void update(int value) override {
        std::cout << "ConcreteObserverB: Received update with value " << value << std::endl;
    }
};

int main() {
    ConcreteSubject subject;

    ConcreteObserverA observerA;
    ConcreteObserverB observerB;

    subject.registerObserver(&observerA);
    subject.registerObserver(&observerB);

    subject.setValue(100); // 触发通知机制

    subject.removeObserver(&observerA);

    subject.setValue(200); // 再次触发通知,只有 observerB 收到通知

    return 0;
}
代码逻辑分析:
  • Observer 类 :是一个抽象类,定义了 update() 方法,所有观察者都必须实现该方法以响应通知。
  • Subject 类 :是一个抽象类,定义了注册、移除和通知观察者的方法。
  • ConcreteSubject 类 :实现了 Subject 接口,维护一个观察者列表,并在 setValue() 方法中调用 notifyObservers() 方法通知所有观察者。
  • ConcreteObserverA 和 ConcreteObserverB 类 :具体观察者类,实现 update() 方法,接收主题的状态变化通知。
参数说明:
  • registerObserver(Observer* observer) :用于将观察者注册到主题中。
  • removeObserver(Observer* observer) :用于从主题中移除指定的观察者。
  • notifyObservers() :遍历所有观察者并调用其 update() 方法。
  • setValue(int newValue) :设置主题的状态值,并触发通知机制。
运行结果:
ConcreteObserverA: Received update with value 100
ConcreteObserverB: Received update with value 100
ConcreteObserverB: Received update with value 200

从输出可以看出,当主题的值发生变化时,所有注册的观察者都会收到通知。当移除一个观察者后,该观察者不再接收后续的通知。

4.3 策略模式详解与C++实现

策略模式是一种行为型设计模式,它允许在运行时选择算法或行为。该模式通过将算法封装在独立的类中,使它们可以互换使用,从而避免了使用大量的条件判断语句。

4.3.1 策略模式的算法族设计

策略模式的核心是定义一个算法族(Strategy Family),每个算法族中的具体算法(Concrete Strategy)都实现相同的接口(Strategy Interface)。上下文(Context)类持有策略接口的引用,通过调用接口方法来执行不同的算法。

其类结构如下:

classDiagram
    class Strategy {
        +execute()
    }
    class ConcreteStrategyA {
        +execute()
    }
    class ConcreteStrategyB {
        +execute()
    }
    class Context {
        -strategy: Strategy
        +setStrategy(Strategy)
        +executeStrategy()
    }

    Strategy <|-- ConcreteStrategyA
    Strategy <|-- ConcreteStrategyB
    Context --> Strategy

如上图所示, Context 持有一个 Strategy 接口的引用,并通过调用 executeStrategy() 方法来执行当前策略的 execute() 方法。

4.3.2 在C++中实现动态切换算法

下面是一个使用C++实现的策略模式示例,演示如何根据不同的策略执行不同的排序算法。

#include <iostream>
#include <vector>
#include <algorithm>

// 定义策略接口
class SortingStrategy {
public:
    virtual void sort(std::vector<int>& data) = 0;
};

// 具体策略A:使用标准库排序
class StdSortStrategy : public SortingStrategy {
public:
    void sort(std::vector<int>& data) override {
        std::sort(data.begin(), data.end());
    }
};

// 具体策略B:使用冒泡排序
class BubbleSortStrategy : public SortingStrategy {
public:
    void sort(std::vector<int>& data) override {
        int n = data.size();
        for (int i = 0; i < n - 1; ++i) {
            for (int j = 0; j < n - i - 1; ++j) {
                if (data[j] > data[j + 1]) {
                    std::swap(data[j], data[j + 1]);
                }
            }
        }
    }
};

// 上下文类
class Sorter {
private:
    SortingStrategy* strategy;

public:
    void setStrategy(SortingStrategy* newStrategy) {
        strategy = newStrategy;
    }

    void executeSort(std::vector<int>& data) {
        if (strategy) {
            strategy->sort(data);
        }
    }
};

int main() {
    std::vector<int> data = {5, 2, 9, 1, 5, 6};

    Sorter sorter;
    StdSortStrategy stdSort;
    BubbleSortStrategy bubbleSort;

    // 使用标准库排序
    sorter.setStrategy(&stdSort);
    sorter.executeSort(data);
    std::cout << "After StdSort: ";
    for (int num : data) std::cout << num << " ";
    std::cout << std::endl;

    // 重新赋值数据
    data = {7, 3, 8, 2, 1, 4};

    // 使用冒泡排序
    sorter.setStrategy(&bubbleSort);
    sorter.executeSort(data);
    std::cout << "After BubbleSort: ";
    for (int num : data) std::cout << num << " ";
    std::cout << std::endl;

    return 0;
}
代码逻辑分析:
  • SortingStrategy 接口 :定义了排序算法的公共接口 sort()
  • StdSortStrategy 类 :实现使用 C++ 标准库的 std::sort() 方法进行排序。
  • BubbleSortStrategy 类 :实现冒泡排序算法。
  • Sorter 类 :上下文类,持有策略接口指针,并提供设置策略和执行排序的方法。
参数说明:
  • setStrategy(SortingStrategy* newStrategy) :设置当前使用的排序策略。
  • executeSort(std::vector<int>& data) :执行当前策略的排序方法。
运行结果:
After StdSort: 1 2 5 5 6 9 
After BubbleSort: 1 2 3 4 7 8

从输出可以看出,根据不同的策略, Sorter 类可以动态切换排序算法。

4.4 模板方法模式详解与C++实现

模板方法模式是一种行为型设计模式,它定义了一个算法的骨架,并将一些步骤延迟到子类中实现。该模式允许子类在不改变算法结构的前提下重新定义某些步骤。

4.4.1 模板方法在抽象类中的定义

模板方法模式的核心是定义一个抽象类,其中包含一个模板方法(Template Method)和若干抽象方法(Primitive Operations)。模板方法定义了算法的骨架,而抽象方法由子类实现,以完成特定步骤。

其类结构如下:

classDiagram
    class AbstractClass {
        +templateMethod()
        +primitiveOperation1()
        +primitiveOperation2()
    }
    class ConcreteClass {
        +primitiveOperation1()
        +primitiveOperation2()
    }

    AbstractClass <|-- ConcreteClass

如上图所示, AbstractClass 定义了 templateMethod() 方法,该方法调用了两个抽象方法 primitiveOperation1() primitiveOperation2() ConcreteClass 实现这两个方法以完成特定的步骤。

4.4.2 使用C++实现算法骨架与子类扩展

下面是一个使用C++实现的模板方法模式示例,演示如何定义一个数据库操作模板。

#include <iostream>

// 抽象类,定义模板方法和基本操作
class DatabaseTemplate {
public:
    void execute() {
        connect();
        executeQuery();
        disconnect();
    }

protected:
    virtual void connect() = 0;
    virtual void executeQuery() = 0;
    virtual void disconnect() = 0;
};

// 具体子类:MySQL 实现
class MySQLDatabase : public DatabaseTemplate {
protected:
    void connect() override {
        std::cout << "Connecting to MySQL database..." << std::endl;
    }

    void executeQuery() override {
        std::cout << "Executing MySQL query..." << std::endl;
    }

    void disconnect() override {
        std::cout << "Disconnecting from MySQL database..." << std::endl;
    }
};

// 具体子类:PostgreSQL 实现
class PostgreSQLDatabase : public DatabaseTemplate {
protected:
    void connect() override {
        std::cout << "Connecting to PostgreSQL database..." << std::endl;
    }

    void executeQuery() override {
        std::cout << "Executing PostgreSQL query..." << std::endl;
    }

    void disconnect() override {
        std::cout << "Disconnecting from PostgreSQL database..." << std::endl;
    }
};

int main() {
    MySQLDatabase mysql;
    std::cout << "Using MySQL:\n";
    mysql.execute();

    std::cout << "\nUsing PostgreSQL:\n";
    PostgreSQLDatabase postgres;
    postgres.execute();

    return 0;
}
代码逻辑分析:
  • DatabaseTemplate 类 :定义了数据库操作的模板方法 execute() ,该方法调用 connect() executeQuery() disconnect() 三个抽象方法。
  • MySQLDatabase 类 :实现 MySQL 数据库的具体连接、查询和断开操作。
  • PostgreSQLDatabase 类 :实现 PostgreSQL 数据库的具体连接、查询和断开操作。
参数说明:
  • execute() :模板方法,定义数据库操作的整体流程。
  • connect() :连接数据库的具体实现。
  • executeQuery() :执行查询的具体实现。
  • disconnect() :断开连接的具体实现。
运行结果:
Using MySQL:
Connecting to MySQL database...
Executing MySQL query...
Disconnecting from MySQL database...

Using PostgreSQL:
Connecting to PostgreSQL database...
Executing PostgreSQL query...
Disconnecting from PostgreSQL database...

从输出可以看出,模板方法定义了算法的骨架,而子类实现了具体的步骤。这种方式使得我们可以复用模板方法的结构,同时灵活地实现不同的数据库操作逻辑。


本章详细介绍了行为型模式中的观察者模式、策略模式和模板方法模式,并结合 C++ 示例展示了它们的实现方式。这些模式在实际开发中具有广泛的应用价值,能够有效提升系统的灵活性和可维护性。

5. C++面向对象特性与设计模式结合应用

面向对象编程(OOP)是现代软件开发的核心思想,C++作为一门支持面向对象特性的语言,其封装、继承、多态等机制为设计模式的实现提供了坚实基础。设计模式的本质是对面向对象设计原则的抽象与复用,而C++语言的特性则为这些模式的落地提供了高效的实现手段。本章将深入探讨面向对象特性在设计模式中的体现方式,并通过具体代码示例,展示如何在C++中结合继承与组合策略来优化模式的实现,同时结合C++标准模板库(STL)进一步提升设计模式的效率与可维护性。

5.1 面向对象特性概述

C++的面向对象特性主要包括封装、继承和多态。这些特性不仅构成了OOP的基础,也直接影响了设计模式的实现方式。

5.1.1 封装、继承与多态在设计模式中的体现

封装(Encapsulation)是将数据与行为封装在类中,通过访问控制(如public、private、protected)对外暴露接口。在设计模式中,封装常用于定义抽象接口和隐藏实现细节。例如,在 工厂模式 中,具体产品的创建过程被封装在工厂类中,客户端只需调用统一的接口即可获取对象。

继承(Inheritance)允许一个类(子类)继承另一个类(父类)的属性和方法。继承是实现代码复用的重要机制,同时也支持多态。然而,在设计模式中,继承往往带来较高的耦合度。例如, 策略模式 通过接口继承实现算法族的切换,但过度依赖继承会导致系统难以扩展和维护。

多态(Polymorphism)允许不同子类对同一接口做出不同响应。在C++中,多态主要通过虚函数实现。多态是实现 观察者模式 模板方法模式 等行为型模式的关键机制。例如,在 观察者模式 中,多个观察者类继承相同的接口,并通过虚函数实现各自的更新逻辑。

以下是一个简单的多态示例,展示了不同观察者如何实现统一接口:

#include <iostream>
#include <vector>

class Observer {
public:
    virtual void update() = 0;  // 纯虚函数,定义统一接口
};

class ConcreteObserverA : public Observer {
public:
    void update() override {
        std::cout << "Observer A received update." << std::endl;
    }
};

class ConcreteObserverB : public Observer {
public:
    void update() override {
        std::cout << "Observer B received update." << std::endl;
    }
};

class Subject {
private:
    std::vector<Observer*> observers;
public:
    void attach(Observer* observer) {
        observers.push_back(observer);
    }

    void notify() {
        for (auto observer : observers) {
            observer->update();  // 多态调用
        }
    }
};

int main() {
    Subject subject;
    ConcreteObserverA observerA;
    ConcreteObserverB observerB;

    subject.attach(&observerA);
    subject.attach(&observerB);

    subject.notify();  // 触发多态更新
    return 0;
}

代码逻辑分析:

  • Observer 类定义了一个纯虚函数 update() ,作为所有观察者的统一接口。
  • ConcreteObserverA ConcreteObserverB 分别实现了 update() 方法,展示了多态行为。
  • Subject 类维护观察者列表,并在 notify() 方法中调用每个观察者的 update()
  • main() 函数中通过 attach() 注册观察者,并调用 notify() 实现事件广播。

该示例充分体现了多态在行为型模式中的核心作用,同时也展示了封装与继承如何协同工作,构建灵活的观察者系统。

5.1.2 C++虚函数与接口设计的结合

C++中没有原生的“接口”类型,但可以通过纯虚类(含纯虚函数的类)模拟接口行为。纯虚函数定义了接口规范,而子类必须实现这些函数。这种机制广泛应用于设计模式中,尤其是在 策略模式 适配器模式 装饰器模式 等中。

策略模式 为例,我们可以定义一个策略接口:

class Strategy {
public:
    virtual int execute(int a, int b) = 0;  // 策略接口
    virtual ~Strategy() {}  // 虚析构函数确保正确析构
};

class AddStrategy : public Strategy {
public:
    int execute(int a, int b) override {
        return a + b;
    }
};

class MultiplyStrategy : public Strategy {
public:
    int execute(int a, int b) override {
        return a * b;
    }
};

class Context {
private:
    Strategy* strategy;
public:
    void setStrategy(Strategy* s) {
        strategy = s;
    }

    int executeStrategy(int a, int b) {
        return strategy->execute(a, b);
    }
};

逻辑分析:

  • Strategy 类定义了策略接口 execute() ,作为所有具体策略的基类。
  • AddStrategy MultiplyStrategy 分别实现加法和乘法策略。
  • Context 类持有策略对象,并通过 executeStrategy() 调用策略接口。
  • 这种方式允许运行时动态切换策略,体现了策略模式的核心思想。
特性 封装 继承 多态 接口模拟
是否使用
作用 隐藏实现细节 扩展策略类 动态调用不同策略 定义统一接口

表格展示了该模式中各个OOP特性的使用情况,可以看出,它们共同构成了策略模式的核心结构。

5.2 设计模式中的继承与组合策略

虽然继承在设计模式中非常常见,但它往往带来较高的耦合度。组合(Composition)则是一种更灵活的设计方式,通过对象的组合关系实现功能扩展,避免了继承的缺点。

5.2.1 继承带来的耦合问题与组合的优势

继承的缺点主要体现在:

  • 紧耦合 :子类依赖父类的具体实现,修改父类可能影响所有子类。
  • 类爆炸 :多个功能组合时,继承可能导致类数量急剧增长。

装饰器模式 为例,若采用继承方式为对象添加功能,代码将变得臃肿且难以维护。而使用组合方式,则可以动态地为对象添加功能,而无需修改原有类。

下面是一个使用组合实现的装饰器模式示例:

class Component {
public:
    virtual void operation() = 0;
    virtual ~Component() {}
};

class ConcreteComponent : public Component {
public:
    void operation() override {
        std::cout << "Basic operation." << std::endl;
    }
};

class Decorator : public Component {
protected:
    Component* component;
public:
    Decorator(Component* c) : component(c) {}
    void operation() override {
        component->operation();
    }
};

class ConcreteDecoratorA : public Decorator {
public:
    ConcreteDecoratorA(Component* c) : Decorator(c) {}

    void operation() override {
        Decorator::operation();
        addBehavior();
    }

    void addBehavior() {
        std::cout << "Decorator A adds behavior." << std::endl;
    }
};

class ConcreteDecoratorB : public Decorator {
public:
    ConcreteDecoratorB(Component* c) : Decorator(c) {}

    void operation() override {
        Decorator::operation();
        addBehavior();
    }

    void addBehavior() {
        std::cout << "Decorator B adds behavior." << std::endl;
    }
};

代码分析:

  • Component 是接口类,定义了 operation() 方法。
  • ConcreteComponent 实现了基础操作。
  • Decorator 是装饰器基类,持有一个 Component 对象。
  • ConcreteDecoratorA ConcreteDecoratorB 通过组合方式在原有操作基础上添加新功能。

组合优势:

  • 灵活性高 :可以在运行时动态组合多个装饰器。
  • 低耦合 :装饰器与被装饰对象无强依赖。
  • 易于扩展 :新增装饰器无需修改已有类。

5.2.2 在C++中使用组合替代继承的实践

为了进一步展示组合的优势,我们可以对比继承和组合两种方式实现的 策略模式

实现方式 优点 缺点 适用场景
继承 简单直观 耦合高,扩展困难 固定行为
组合 灵活,解耦 结构稍复杂 动态行为切换

例如,使用组合方式实现的策略模式如下:

class Operation {
public:
    virtual int compute(int a, int b) = 0;
    virtual ~Operation() {}
};

class Calculator {
private:
    Operation* op;
public:
    void setOperation(Operation* o) { op = o; }
    int calculate(int a, int b) { return op->compute(a, b); }
};

class Add : public Operation {
public:
    int compute(int a, int b) override { return a + b; }
};

class Multiply : public Operation {
public:
    int compute(int a, int b) override { return a * b; }
};

在这个结构中, Calculator 通过组合的方式持有 Operation 接口,实现了动态策略切换。

mermaid流程图:组合结构图

classDiagram
    class Operation {
        <<interface>>
        +compute(int, int) int
    }

    class Add {
        +compute(int, int) int
    }

    class Multiply {
        +compute(int, int) int
    }

    class Calculator {
        -Operation* op
        +setOperation(Operation*)
        +calculate(int, int) int
    }

    Operation <|-- Add
    Operation <|-- Multiply
    Calculator --> Operation

该图展示了组合结构的清晰关系,体现了接口与实现的解耦特性。

5.3 设计模式与C++ STL的结合

C++标准模板库(STL)提供了丰富的容器和算法,可以与设计模式结合使用,提升代码的效率和可维护性。

5.3.1 使用STL容器与算法优化模式实现

许多设计模式涉及集合管理,如 观察者模式 中的观察者列表、 工厂模式 中的对象池等。STL容器(如 vector , map , set )为这些集合操作提供了高效的实现方式。

观察者模式 为例,我们使用 std::vector 存储观察者:

#include <vector>
#include <algorithm>

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

class Subject {
private:
    std::vector<Observer*> observers;
public:
    void attach(Observer* o) {
        observers.push_back(o);
    }

    void detach(Observer* o) {
        observers.erase(std::remove(observers.begin(), observers.end(), o), observers.end());
    }

    void notify() {
        for (auto o : observers) {
            o->update();
        }
    }
};

优势:

  • 使用 std::vector 管理观察者,简化内存管理和遍历逻辑。
  • 利用 std::remove erase 实现高效的观察者移除。

5.3.2 模式在C++标准库中的应用实例

C++标准库中也广泛使用了设计模式的思想,例如:

  • 迭代器模式(Iterator Pattern) std::vector , std::list 等容器通过 begin() , end() 提供统一的迭代接口。
  • 适配器模式(Adapter Pattern) std::stack , std::queue 是基于 std::deque 的适配器。
  • 工厂模式(Factory Pattern) std::make_shared<T>() 是创建共享指针的工厂方法。

例如, std::shared_ptr 的创建过程可以看作是工厂模式的应用:

#include <memory>

class Product {
public:
    virtual void use() = 0;
};

class ConcreteProduct : public Product {
public:
    void use() override {
        std::cout << "Using concrete product." << std::endl;
    }
};

std::shared_ptr<Product> createProduct() {
    return std::make_shared<ConcreteProduct>();
}

int main() {
    auto p = createProduct();
    p->use();
    return 0;
}

逻辑分析:

  • createProduct() 是一个工厂函数,返回 shared_ptr 智能指针。
  • std::make_shared 是工厂方法的典型应用,避免了手动 new delete

这种结合方式不仅提升了代码的可读性和安全性,也体现了现代C++编程中对设计模式的自然融合。

通过本章内容的探讨,我们深入了解了C++面向对象特性在设计模式中的应用方式,并通过实际代码展示了继承与组合在模式实现中的优劣对比,同时结合STL库进一步提升了设计模式的实现效率和可维护性。

6. 设计模式在实际开发中的最佳实践

6.1 实际开发中设计模式的选择策略

6.1.1 模式适用性的评估标准

在实际项目开发中,选择合适的设计模式是关键。以下是几个重要的评估标准:

  • 问题匹配度 :设计模式必须能够解决当前面临的问题。例如,若系统中存在多个相似对象的创建逻辑,可以考虑使用工厂模式或建造者模式。
  • 维护性 :模式应有助于系统的可维护性和扩展性。例如,策略模式可以帮助我们动态切换算法,提升代码的可扩展性。
  • 耦合度 :优先选择降低模块间耦合的设计模式。如观察者模式有助于实现松耦合的事件通知机制。
  • 性能影响 :部分设计模式(如装饰器模式)可能引入额外的对象层级,从而影响性能,需权衡使用。
  • 开发成本 :有些模式实现较为复杂,需要额外的类和接口,可能会增加初期开发成本。

6.1.2 模式与系统架构设计的匹配

设计模式的选择应与整体系统架构保持一致:

  • 分层架构 :适配器模式、外观模式有助于模块间的接口统一。
  • 微服务架构 :代理模式常用于远程服务调用,如RPC框架中。
  • 事件驱动架构 :观察者模式天然适合事件通知机制。
  • 插件化架构 :策略模式、工厂模式可支持插件的动态加载与替换。

例如,在一个基于插件的系统中,使用工厂模式来创建插件实例,并通过策略模式定义插件的行为,可以实现灵活的插件管理。

// 策略接口
class PluginStrategy {
public:
    virtual void execute() = 0;
};

// 具体策略A
class PluginA : public PluginStrategy {
public:
    void execute() override {
        std::cout << "Executing Plugin A" << std::endl;
    }
};

// 具体策略B
class PluginB : public PluginStrategy {
public:
    void execute() override {
        std::cout << "Executing Plugin B" << std::endl;
    }
};

// 工厂类
class PluginFactory {
public:
    static PluginStrategy* createPlugin(const std::string& type) {
        if (type == "A") return new PluginA();
        if (type == "B") return new PluginB();
        return nullptr;
    }
};

说明:
- PluginStrategy 是策略接口。
- PluginA PluginB 实现具体行为。
- PluginFactory 根据输入字符串创建具体策略实例。

6.2 设计模式在项目中的典型应用场景

6.2.1 在模块解耦、资源管理中的使用

设计模式在模块解耦方面有显著优势:

  • 单例模式 :用于管理全局资源,如日志系统、配置中心。
  • 适配器模式 :使不同模块接口兼容,避免直接修改原有接口。
  • 代理模式 :用于资源访问控制,比如远程调用、延迟加载等场景。

例如,使用单例模式管理数据库连接池:

class DatabaseConnectionPool {
private:
    static DatabaseConnectionPool* instance;
    std::vector<std::string> connections;

    DatabaseConnectionPool() {
        // 初始化连接池
        connections.push_back("conn1");
        connections.push_back("conn2");
    }

public:
    static DatabaseConnectionPool* getInstance() {
        if (!instance) {
            instance = new DatabaseConnectionPool();
        }
        return instance;
    }

    std::string getConnection() {
        if (!connections.empty()) {
            std::string conn = connections.back();
            connections.pop_back();
            return conn;
        }
        return "No available connection";
    }

    void releaseConnection(const std::string& conn) {
        connections.push_back(conn);
    }
};

// 静态成员初始化
DatabaseConnectionPool* DatabaseConnectionPool::instance = nullptr;

说明:
- instance 为单例对象指针。
- getConnection 从池中获取一个连接。
- releaseConnection 将使用完的连接放回池中。

6.2.2 在系统扩展与维护中的应用案例

设计模式有助于系统的扩展与维护,例如:

  • 装饰器模式 :允许在运行时动态添加功能,而无需修改原有代码。
  • 模板方法模式 :定义算法骨架,子类实现具体步骤,增强代码复用。

例如,使用装饰器模式为文本消息添加加密、压缩等处理:

class Message {
public:
    virtual std::string getContent() = 0;
};

class PlainMessage : public Message {
    std::string content;
public:
    PlainMessage(const std::string& content) : content(content) {}
    std::string getContent() override { return content; }
};

class MessageDecorator : public Message {
protected:
    Message* decoratedMessage;
public:
    MessageDecorator(Message* msg) : decoratedMessage(msg) {}
    std::string getContent() override { return decoratedMessage->getContent(); }
};

class EncryptedMessage : public MessageDecorator {
public:
    EncryptedMessage(Message* msg) : MessageDecorator(msg) {}
    std::string getContent() override {
        std::string original = MessageDecorator::getContent();
        // 简单加密:反转字符串
        std::reverse(original.begin(), original.end());
        return "[Encrypted] " + original;
    }
};

class CompressedMessage : public MessageDecorator {
public:
    CompressedMessage(Message* msg) : MessageDecorator(msg) {}
    std::string getContent() override {
        std::string original = MessageDecorator::getContent();
        // 简单压缩:截断字符串
        if (original.length() > 20) original = original.substr(0, 20) + "...";
        return "[Compressed] " + original;
    }
};

使用示例:

int main() {
    Message* msg = new PlainMessage("Hello Design Patterns!");
    msg = new EncryptedMessage(msg);
    msg = new CompressedMessage(msg);

    std::cout << msg->getContent() << std::endl;
    return 0;
}

输出:

[Compressed] [Encrypted] !srettnapSniarTn...

分析:
- 通过装饰器模式,可以灵活地组合功能,而无需修改原始类。
- 这种方式在系统维护和功能扩展时非常有效。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:设计模式是软件工程中的核心概念,代表在特定场景下解决常见问题的最佳实践与可复用方案。本套C++设计模式PPT深入讲解了设计模式的基本原理与在C++语言中的具体实现方式,适合初学者系统学习。内容涵盖创建型、结构型和行为型三大类模式,通过实例代码帮助理解如何在实际开发中应用这些模式,提升代码的可读性、可维护性与可扩展性。同时强调设计模式的合理使用,避免过度依赖,结合C++特性实现高质量软件架构。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐