23 种设计模式完整指南 - C++实现详解
23 种设计模式完整指南 - C++实现详解
目录
设计模式概览
设计模式是解决软件设计中常见问题的可重用方案。它们提供了经过验证的解决方案,帮助开发者编写更优雅、可维护和可扩展的代码。
设计模式分类
| 类型 | 数量 | 描述 | 难度 | 
|---|---|---|---|
| 创建型模式 | 5 种 | 关注对象的创建过程 | ⭐⭐ | 
| 结构型模式 | 7 种 | 处理类或对象的组合 | ⭐⭐⭐ | 
| 行为型模式 | 11 种 | 描述对象间的交互 | ⭐⭐⭐⭐ | 
设计原则
SOLID 原则
- 单一职责原则 (SRP) - 一个类应该只有一个职责
 - 开放封闭原则 (OCP) - 对扩展开放,对修改关闭
 - 里氏替换原则 (LSP) - 子类应该能够替换父类
 - 接口隔离原则 (ISP) - 客户端不应该被迫依赖它们不使用的接口
 - 依赖倒置原则 (DIP) - 依赖抽象,而不是具体实现
 
其他重要原则
- 组合复用原则 - 优先使用组合而不是继承
 - 迪米特法则 - 最少知识原则
 - 面向接口编程 - 而不是面向实现编程
 - 封装变化 - 将变化的部分封装起来
 
创建型模式
创建型模式关注对象的创建过程,它们将系统与对象的创建、组合和表示方式解耦。
1. 单例模式 (Singleton)
概念:确保一个类只有一个实例,并提供一个全局访问点。
使用场景:
- 配置管理器
 - 日志记录器
 - 数据库连接池
 - 缓存管理器
 
C++实现:
class Singleton {
private:
    // 私有构造函数防止外部实例化
    Singleton() {}
    
    // 删除拷贝构造函数和赋值运算符
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
public:
    // 线程安全的静态方法获取实例
    static Singleton& getInstance() {
        static Singleton instance;
        return instance;
    }
    
    void doSomething() {
        std::cout << "Singleton operation" << std::endl;
    }
};
// 使用示例
int main() {
    Singleton& instance = Singleton::getInstance();
    instance.doSomething();
    return 0;
}
优点:
- 严格控制实例数量
 - 提供全局访问点
 - 延迟初始化(懒汉式)
 
缺点:
- 可能隐藏依赖关系
 - 单元测试困难
 - 多线程需要考虑线程安全
 
2. 工厂方法模式 (Factory Method)
概念:定义一个创建对象的接口,让子类决定实例化哪个类。
使用场景:
- 对象创建需要灵活性
 - 不知道具体需要创建的对象类型
 - 希望将对象创建延迟到子类
 
C++实现:
// 产品接口
class Product {
public:
    virtual ~Product() {}
    virtual void use() = 0;
};
// 具体产品 A
class ConcreteProductA : public Product {
public:
    void use() override {
        std::cout << "Using Product A" << std::endl;
    }
};
// 具体产品 B
class ConcreteProductB : public Product {
public:
    void use() override {
        std::cout << "Using Product B" << std::endl;
    }
};
// 创建者抽象类
class Creator {
public:
    virtual ~Creator() {}
    
    // 工厂方法
    virtual std::unique_ptr<Product> createProduct() = 0;
    
    // 模板方法,使用工厂方法创建的产品
    void someOperation() {
        auto product = createProduct();
        product->use();
    }
};
// 具体创建者 A
class ConcreteCreatorA : public Creator {
public:
    std::unique_ptr<Product> createProduct() override {
        return std::make_unique<ConcreteProductA>();
    }
};
// 具体创建者 B
class ConcreteCreatorB : public Creator {
public:
    std::unique_ptr<Product> createProduct() override {
        return std::make_unique<ConcreteProductB>();
    }
};
优点:
- 解耦对象的创建和使用
 - 符合开闭原则
 - 更容易扩展新产品类型
 
缺点:
- 增加了类的数量
 - 增加了系统复杂度
 
3. 抽象工厂模式 (Abstract Factory)
概念:提供一个接口,用于创建相关或依赖对象的家族,而无需指定具体类。
使用场景:
- 需要创建一系列相关对象
 - 系统需要独立于产品的创建、组合和表示
 - 需要提供产品类库,只暴露接口
 
C++实现:
// 抽象产品 A
class AbstractProductA {
public:
    virtual ~AbstractProductA() {}
    virtual void operationA() = 0;
};
// 抽象产品 B
class AbstractProductB {
public:
    virtual ~AbstractProductB() {}
    virtual void operationB() = 0;
};
// 具体产品 A1
class ConcreteProductA1 : public AbstractProductA {
public:
    void operationA() override {
        std::cout << "Product A1 operation" << std::endl;
    }
};
// 具体产品 A2
class ConcreteProductA2 : public AbstractProductA {
public:
    void operationA() override {
        std::cout << "Product A2 operation" << std::endl;
    }
};
// 具体产品 B1
class ConcreteProductB1 : public AbstractProductB {
public:
    void operationB() override {
        std::cout << "Product B1 operation" << std::endl;
    }
};
// 具体产品 B2
class ConcreteProductB2 : public AbstractProductB {
public:
    void operationB() override {
        std::cout << "Product B2 operation" << std::endl;
    }
};
// 抽象工厂
class AbstractFactory {
public:
    virtual ~AbstractFactory() {}
    virtual std::unique_ptr<AbstractProductA> createProductA() = 0;
    virtual std::unique_ptr<AbstractProductB> createProductB() = 0;
};
// 具体工厂 1
class ConcreteFactory1 : public AbstractFactory {
public:
    std::unique_ptr<AbstractProductA> createProductA() override {
        return std::make_unique<ConcreteProductA1>();
    }
    
    std::unique_ptr<AbstractProductB> createProductB() override {
        return std::make_unique<ConcreteProductB1>();
    }
};
// 具体工厂 2
class ConcreteFactory2 : public AbstractFactory {
public:
    std::unique_ptr<AbstractProductA> createProductA() override {
        return std::make_unique<ConcreteProductA2>();
    }
    
    std::unique_ptr<AbstractProductB> createProductB() override {
        return std::make_unique<ConcreteProductB2>();
    }
};
优点:
- 确保产品族的一致性
 - 易于交换产品系列
 - 符合开闭原则
 
缺点:
- 难以支持新种类的产品
 - 增加了系统复杂度
 
4. 建造者模式 (Builder)
概念:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
使用场景:
- 创建复杂对象
 - 对象的构建过程独立于其组成部分
 - 需要构建不同表示的复杂对象
 
C++实现:
// 产品类
class Product {
private:
    std::string partA_;
    std::string partB_;
    std::string partC_;
    
public:
    void setPartA(const std::string& part) { partA_ = part; }
    void setPartB(const std::string& part) { partB_ = part; }
    void setPartC(const std::string& part) { partC_ = part; }
    
    void show() {
        std::cout << "Product parts: " << partA_ << ", " << partB_ << ", " << partC_ << std::endl;
    }
};
// 抽象建造者
class Builder {
public:
    virtual ~Builder() {}
    virtual void buildPartA() = 0;
    virtual void buildPartB() = 0;
    virtual void buildPartC() = 0;
    virtual std::unique_ptr<Product> getResult() = 0;
};
// 具体建造者
class ConcreteBuilder : public Builder {
private:
    std::unique_ptr<Product> product_;
    
public:
    ConcreteBuilder() : product_(std::make_unique<Product>()) {}
    
    void buildPartA() override {
        product_->setPartA("PartA");
    }
    
    void buildPartB() override {
        product_->setPartB("PartB");
    }
    
    void buildPartC() override {
        product_->setPartC("PartC");
    }
    
    std::unique_ptr<Product> getResult() override {
        return std::move(product_);
    }
};
// 导演者
class Director {
private:
    std::unique_ptr<Builder> builder_;
    
public:
    void setBuilder(std::unique_ptr<Builder> builder) {
        builder_ = std::move(builder);
    }
    
    std::unique_ptr<Product> construct() {
        builder_->buildPartA();
        builder_->buildPartB();
        builder_->buildPartC();
        return builder_->getResult();
    }
};
优点:
- 构建过程清晰
 - 易于扩展新的建造者
 - 更好地控制构建过程
 
缺点:
- 增加了类的数量
 - 只适用于创建复杂对象
 
5. 原型模式 (Prototype)
概念:通过复制现有的实例来创建新的实例,而不是通过新建类。
使用场景:
- 创建对象成本较高
 - 需要大量相似对象
 - 运行时动态指定对象类型
 
C++实现:
#include <memory>
#include <string>
#include <unordered_map>
// 原型接口
class Prototype {
public:
    virtual ~Prototype() {}
    virtual std::unique_ptr<Prototype> clone() = 0;
    virtual void display() = 0;
};
// 具体原型 A
class ConcretePrototypeA : public Prototype {
private:
    std::string data_;
    
public:
    ConcretePrototypeA(const std::string& data) : data_(data) {}
    
    std::unique_ptr<Prototype> clone() override {
        return std::make_unique<ConcretePrototypeA>(*this);
    }
    
    void display() override {
        std::cout << "Prototype A: " << data_ << std::endl;
    }
};
// 具体原型 B
class ConcretePrototypeB : public Prototype {
private:
    int value_;
    
public:
    ConcretePrototypeB(int value) : value_(value) {}
    
    std::unique_ptr<Prototype> clone() override {
        return std::make_unique<ConcretePrototypeB>(*this);
    }
    
    void display() override {
        std::cout << "Prototype B: " << value_ << std::endl;
    }
};
// 原型管理器
class PrototypeManager {
private:
    std::unordered_map<std::string, std::unique_ptr<Prototype>> prototypes_;
    
public:
    void registerPrototype(const std::string& name, std::unique_ptr<Prototype> prototype) {
        prototypes_[name] = std::move(prototype);
    }
    
    std::unique_ptr<Prototype> create(const std::string& name) {
        if (prototypes_.find(name) != prototypes_.end()) {
            return prototypes_[name]->clone();
        }
        return nullptr;
    }
};
优点:
- 避免了重复的初始化过程
 - 可以动态添加或删除原型
 - 隐藏了具体的产品类
 
缺点:
- 需要实现克隆方法
 - 深拷贝和浅拷贝的问题
 
结构型模式
结构型模式处理类或对象的组合,它们描述如何将类或对象组合成更大的结构。
6. 适配器模式 (Adapter)
概念:将一个类的接口转换成客户期望的另一个接口,使得原本由于接口不兼容而无法一起工作的类可以一起工作。
使用场景:
- 需要使用现有类,但其接口不符合要求
 - 希望创建一个可重用的类,与多个不相关的类合作
 - 需要统一多个类的接口
 
C++实现:
// 目标接口
class Target {
public:
    virtual ~Target() {}
    virtual void request() = 0;
};
// 需要适配的类
class Adaptee {
public:
    void specificRequest() {
        std::cout << "Adaptee: specific request" << std::endl;
    }
};
// 对象适配器
class ObjectAdapter : public Target {
private:
    std::unique_ptr<Adaptee> adaptee_;
    
public:
    ObjectAdapter() : adaptee_(std::make_unique<Adaptee>()) {}
    
    void request() override {
        std::cout << "Adapter: translating request..." << std::endl;
        adaptee_->specificRequest();
    }
};
// 类适配器
class ClassAdapter : public Target, private Adaptee {
public:
    void request() override {
        std::cout << "ClassAdapter: translating request..." << std::endl;
        specificRequest();
    }
};
优点:
- 提高了类的复用性
 - 增加了类的透明度
 - 灵活性好
 
缺点:
- 过多使用适配器会使系统凌乱
 - 增加了系统的复杂度
 
7. 桥接模式 (Bridge)
概念:将抽象部分与它的实现部分分离,使它们可以独立变化。
使用场景:
- 需要在抽象和实现之间增加灵活性
 - 抽象和实现都应该可以通过子类化扩展
 - 实现的变化不应该影响客户端
 
C++实现:
// 实现接口
class Implementor {
public:
    virtual ~Implementor() {}
    virtual void operationImpl() = 0;
};
class ConcreteImplementorA : public Implementor {
public:
    void operationImpl() override {
        std::cout << "ConcreteImplementorA operation" << std::endl;
    }
};
class ConcreteImplementorB : public Implementor {
public:
    void operationImpl() override {
        std::cout << "ConcreteImplementorB operation" << std::endl;
    }
};
// 抽象接口
class Abstraction {
protected:
    std::unique_ptr<Implementor> implementor_;
    
public:
    Abstraction(std::unique_ptr<Implementor> impl) : implementor_(std::move(impl)) {}
    virtual ~Abstraction() {}
    
    virtual void operation() {
        implementor_->operationImpl();
    }
};
class RefinedAbstraction : public Abstraction {
public:
    using Abstraction::Abstraction;
    
    void operation() override {
        std::cout << "RefinedAbstraction: ";
        implementor_->operationImpl();
    }
};
优点:
- 分离了接口和实现
 - 提高了可扩展性
 - 符合开闭原则
 
缺点:
- 增加了系统的理解和设计难度
 - 需要正确识别出系统中两个独立变化的维度
 
8. 组合模式 (Composite)
概念:将对象组合成树形结构以表示"部分-整体"的层次结构,使得客户可以一致地对待单个对象和对象组合。
使用场景:
- 需要表示对象的部分-整体层次结构
 - 希望用户忽略组合对象与单个对象的不同
 - 需要统一地处理所有对象
 
C++实现:
#include <vector>
#include <algorithm>
// 组件接口
class Component {
public:
    virtual ~Component() {}
    virtual void operation() = 0;
    virtual void add(std::unique_ptr<Component> component) {}
    virtual void remove(Component* component) {}
    virtual Component* getChild(int index) { return nullptr; }
};
// 叶子节点
class Leaf : public Component {
private:
    std::string name_;
    
public:
    Leaf(const std::string& name) : name_(name) {}
    
    void operation() override {
        std::cout << "Leaf: " << name_ << std::endl;
    }
};
// 复合节点
class Composite : public Component {
private:
    std::vector<std::unique_ptr<Component>> children_;
    std::string name_;
    
public:
    Composite(const std::string& name) : name_(name) {}
    
    void operation() override {
        std::cout << "Composite: " << name_ << std::endl;
        for (const auto& child : children_) {
            child->operation();
        }
    }
    
    void add(std::unique_ptr<Component> component) override {
        children_.push_back(std::move(component));
    }
    
    void remove(Component* component) override {
        children_.erase(
            std::remove_if(children_.begin(), children_.end(),
                [component](const std::unique_ptr<Component>& ptr) {
                    return ptr.get() == component;
                }),
            children_.end()
        );
    }
    
    Component* getChild(int index) override {
        if (index >= 0 && index < children_.size()) {
            return children_[index].get();
        }
        return nullptr;
    }
};
优点:
- 简化了客户端代码
 - 更容易添加新类型的组件
 - 符合开闭原则
 
缺点:
- 难以限制组合中的组件类型
 - 可能会使设计过于一般化
 
9. 装饰模式 (Decorator)
概念:动态地给一个对象添加一些额外的职责,提供了比继承更灵活的扩展功能的方式。
使用场景:
- 需要动态地给对象添加功能
 - 需要撤销功能
 - 当不能采用继承的方式扩展系统时
 
C++实现:
// 基础组件接口
class Coffee {
public:
    virtual ~Coffee() {}
    virtual double cost() = 0;
    virtual std::string description() = 0;
};
// 具体组件
class SimpleCoffee : public Coffee {
public:
    double cost() override {
        return 1.0;
    }
    
    std::string description() override {
        return "Simple coffee";
    }
};
// 装饰器基类
class CoffeeDecorator : public Coffee {
protected:
    std::unique_ptr<Coffee> coffee_;
    
public:
    CoffeeDecorator(std::unique_ptr<Coffee> coffee) : coffee_(std::move(coffee)) {}
};
// 具体装饰器 - 牛奶
class MilkDecorator : public CoffeeDecorator {
public:
    MilkDecorator(std::unique_ptr<Coffee> coffee) : CoffeeDecorator(std::move(coffee)) {}
    
    double cost() override {
        return coffee_->cost() + 0.5;
    }
    
    std::string description() override {
        return coffee_->description() + ", milk";
    }
};
// 具体装饰器 - 糖
class SugarDecorator : public CoffeeDecorator {
public:
    SugarDecorator(std::unique_ptr<Coffee> coffee) : CoffeeDecorator(std::move(coffee)) {}
    
    double cost() override {
        return coffee_->cost() + 0.2;
    }
    
    std::string description() override {
        return coffee_->description() + ", sugar";
    }
};
优点:
- 比继承更灵活
 - 避免了类爆炸
 - 符合开闭原则
 
缺点:
- 会产生许多小对象
 - 调试困难
 
10. 外观模式 (Facade)
概念:为子系统中的一组接口提供一个一致的界面,使得子系统更容易使用。
使用场景:
- 需要简化复杂子系统的使用
 - 需要将子系统与客户端解耦
 - 需要分层设计
 
C++实现:
// 子系统类
class CPU {
public:
    void freeze() { std::cout << "CPU: freeze" << std::endl; }
    void jump(long position) { std::cout << "CPU: jump to " << position << std::endl; }
    void execute() { std::cout << "CPU: execute" << std::endl; }
};
class Memory {
public:
    void load(long position, const std::string& data) {
        std::cout << "Memory: load data at " << position << std::endl;
    }
};
class HardDrive {
public:
    std::string read(long lba, int size) {
        std::cout << "HardDrive: read " << size << " bytes from " << lba << std::endl;
        return "data";
    }
};
// 外观类
class ComputerFacade {
private:
    CPU cpu_;
    Memory memory_;
    HardDrive hardDrive_;
    
public:
    void start() {
        std::cout << "Computer starting..." << std::endl;
        cpu_.freeze();
        memory_.load(0, hardDrive_.read(0, 1024));
        cpu_.jump(0);
        cpu_.execute();
        std::cout << "Computer started!" << std::endl;
    }
};
优点:
- 简化了接口
 - 解耦了客户端和子系统
 - 更好的层次划分
 
缺点:
- 可能过于简化,无法满足特殊需求
 - 不符合开闭原则(可能需要修改外观类)
 
11. 享元模式 (Flyweight)
概念:运用共享技术来有效地支持大量细粒度对象的复用。
使用场景:
- 系统中存在大量相似对象
 - 需要缓冲池的场景
 - 对象的大部分状态可以外部化
 
C++实现:
#include <map>
// 享元接口
class Flyweight {
public:
    virtual ~Flyweight() {}
    virtual void operation(const std::string& extrinsicState) = 0;
};
// 具体享元
class ConcreteFlyweight : public Flyweight {
private:
    std::string intrinsicState_;
    
public:
    ConcreteFlyweight(const std::string& state) : intrinsicState_(state) {}
    
    void operation(const std::string& extrinsicState) override {
        std::cout << "Intrinsic: " << intrinsicState_ 
                  << ", Extrinsic: " << extrinsicState << std::endl;
    }
};
// 享元工厂
class FlyweightFactory {
private:
    std::map<std::string, std::unique_ptr<Flyweight>> flyweights_;
    
public:
    Flyweight* getFlyweight(const std::string& key) {
        if (flyweights_.find(key) == flyweights_.end()) {
            flyweights_[key] = std::make_unique<ConcreteFlyweight>(key);
        }
        return flyweights_[key].get();
    }
    
    size_t getFlyweightCount() const {
        return flyweights_.size();
    }
};
优点:
- 减少了内存使用
 - 提高了性能
 - 集中管理共享对象
 
缺点:
- 增加了系统复杂度
 - 需要区分内部状态和外部状态
 
12. 代理模式 (Proxy)
概念:为其他对象提供一种代理以控制对这个对象的访问。
使用场景:
- 需要控制对对象的访问
 - 需要延迟加载
 - 需要远程访问
 
C++实现:
// 主题接口
class Subject {
public:
    virtual ~Subject() {}
    virtual void request() = 0;
};
// 真实主题
class RealSubject : public Subject {
public:
    void request() override {
        std::cout << "RealSubject: handling request" << std::endl;
    }
};
// 代理类
class Proxy : public Subject {
private:
    std::unique_ptr<RealSubject> realSubject_;
    
    void checkAccess() {
        std::cout << "Proxy: checking access" << std::endl;
    }
    
    void logAccess() {
        std::cout << "Proxy: logging access" << std::endl;
    }
    
public:
    void request() override {
        checkAccess();
        if (!realSubject_) {
            realSubject_ = std::make_unique<RealSubject>();
        }
        realSubject_->request();
        logAccess();
    }
};
优点:
- 职责清晰
 - 高扩展性
 - 智能化
 
缺点:
- 增加了系统复杂度
 - 请求处理速度变慢
 
行为型模式
行为型模式关注对象之间的通信和职责分配,它们描述算法和对象间职责的分配。
13. 职责链模式 (Chain of Responsibility)
概念:将请求沿着处理链传递,直到有一个对象处理它。
使用场景:
- 多个对象可以处理同一请求
 - 不明确指定接收者
 - 需要动态指定处理链
 
C++实现:
class Handler {
protected:
    std::unique_ptr<Handler> next_;
    
public:
    virtual ~Handler() {}
    void setNext(std::unique_ptr<Handler> next) {
        next_ = std::move(next);
    }
    
    virtual void handleRequest(const std::string& request) {
        if (next_) {
            next_->handleRequest(request);
        }
    }
};
class ConcreteHandlerA : public Handler {
public:
    void handleRequest(const std::string& request) override {
        if (request == "A") {
            std::cout << "Handler A handled request: " << request << std::endl;
        } else if (next_) {
            next_->handleRequest(request);
        }
    }
};
class ConcreteHandlerB : public Handler {
public:
    void handleRequest(const std::string& request) override {
        if (request == "B") {
            std::cout << "Handler B handled request: " << request << std::endl;
        } else if (next_) {
            next_->handleRequest(request);
        }
    }
};
优点:
- 降低了耦合度
 - 增强了系统的可扩展性
 - 增强了给对象指派职责的灵活性
 
缺点:
- 不能保证请求一定被接收
 - 系统性能可能受到影响
 - 调试不方便
 
14. 命令模式 (Command)
概念:将请求封装成对象,以便使用不同的请求、队列或日志请求来参数化其他对象。
使用场景:
- 需要将请求调用者和接收者解耦
 - 需要支持撤销和重做
 - 需要支持命令队列和日志
 
C++实现:
// 接收者
class Receiver {
public:
    void action() {
        std::cout << "Receiver: performing action" << std::endl;
    }
    
    void undoAction() {
        std::cout << "Receiver: undoing action" << std::endl;
    }
};
// 命令接口
class Command {
public:
    virtual ~Command() {}
    virtual void execute() = 0;
    virtual void undo() = 0;
};
// 具体命令
class ConcreteCommand : public Command {
private:
    std::unique_ptr<Receiver> receiver_;
    
public:
    ConcreteCommand(std::unique_ptr<Receiver> receiver) : receiver_(std::move(receiver)) {}
    
    void execute() override {
        receiver_->action();
    }
    
    void undo() override {
        receiver_->undoAction();
    }
};
// 调用者
class Invoker {
private:
    std::stack<std::unique_ptr<Command>> commandHistory_;
    
public:
    void executeCommand(std::unique_ptr<Command> command) {
        command->execute();
        commandHistory_.push(std::move(command));
    }
    
    void undoCommand() {
        if (!commandHistory_.empty()) {
            commandHistory_.top()->undo();
            commandHistory_.pop();
        }
    }
};
优点:
- 降低了系统耦合度
 - 新的命令可以很容易地添加到系统中
 - 可以比较容易地设计一个命令队列和宏命令
 
缺点:
- 可能会导致某些系统有过多的具体命令类
 
15. 解释器模式 (Interpreter)
概念:为语言的语法表示定义一个解释器,使用该解释器来解释语言中的句子。
使用场景:
- 语言的语法比较简单
 - 效率不是主要考虑因素
 - 需要解释执行的语言
 
C++实现:
// 上下文
class Context {
private:
    std::string input_;
    
public:
    Context(const std::string& input) : input_(input) {}
    
    std::string getInput() const { return input_; }
    void setInput(const std::string& input) { input_ = input; }
};
// 抽象表达式
class AbstractExpression {
public:
    virtual ~AbstractExpression() {}
    virtual bool interpret(Context& context) = 0;
};
// 终结符表达式
class TerminalExpression : public AbstractExpression {
private:
    std::string data_;
    
public:
    TerminalExpression(const std::string& data) : data_(data) {}
    
    bool interpret(Context& context) override {
        return context.getInput().find(data_) != std::string::npos;
    }
};
// 或表达式
class OrExpression : public AbstractExpression {
private:
    std::unique_ptr<AbstractExpression> expr1_;
    std::unique_ptr<AbstractExpression> expr2_;
    
public:
    OrExpression(std::unique_ptr<AbstractExpression> expr1, 
                 std::unique_ptr<AbstractExpression> expr2)
        : expr1_(std::move(expr1)), expr2_(std::move(expr2)) {}
    
    bool interpret(Context& context) override {
        return expr1_->interpret(context) || expr2_->interpret(context);
    }
};
// 与表达式
class AndExpression : public AbstractExpression {
private:
    std::unique_ptr<AbstractExpression> expr1_;
    std::unique_ptr<AbstractExpression> expr2_;
    
public:
    AndExpression(std::unique_ptr<AbstractExpression> expr1, 
                  std::unique_ptr<AbstractExpression> expr2)
        : expr1_(std::move(expr1)), expr2_(std::move(expr2)) {}
    
    bool interpret(Context& context) override {
        return expr1_->interpret(context) && expr2_->interpret(context);
    }
};
优点:
- 易于改变和扩展文法
 - 实现文法比较简单
 
缺点:
- 复杂的文法难以维护
 - 解释器模式会引起类膨胀
 - 解释器模式采用递归调用方法
 
16. 迭代器模式 (Iterator)
概念:提供一种方法顺序访问聚合对象中的各个元素,而不暴露其内部表示。
使用场景:
- 需要访问聚合对象的内容而不暴露内部表示
 - 需要支持多种遍历方式
 - 需要为不同的聚合结构提供统一的遍历接口
 
C++实现:
template<typename T>
class Iterator {
public:
    virtual ~Iterator() {}
    virtual bool hasNext() = 0;
    virtual T next() = 0;
};
// 聚合接口
template<typename T>
class Aggregate {
public:
    virtual ~Aggregate() {}
    virtual std::unique_ptr<Iterator<T>> createIterator() = 0;
    virtual void add(const T& item) = 0;
    virtual T get(int index) = 0;
    virtual int size() = 0;
};
// 具体聚合
template<typename T>
class ConcreteAggregate : public Aggregate<T> {
private:
    std::vector<T> items_;
    
public:
    std::unique_ptr<Iterator<T>> createIterator() override;
    void add(const T& item) override { items_.push_back(item); }
    T get(int index) override { return items_[index]; }
    int size() override { return items_.size(); }
};
// 具体迭代器
template<typename T>
class ConcreteIterator : public Iterator<T> {
private:
    ConcreteAggregate<T>* aggregate_;
    int current_;
    
public:
    ConcreteIterator(ConcreteAggregate<T>* aggregate) 
        : aggregate_(aggregate), current_(0) {}
    
    bool hasNext() override {
        return current_ < aggregate_->size();
    }
    
    T next() override {
        return aggregate_->get(current_++);
    }
};
template<typename T>
std::unique_ptr<Iterator<T>> ConcreteAggregate<T>::createIterator() {
    return std::make_unique<ConcreteIterator<T>>(this);
}
优点:
- 支持以不同的方式遍历一个聚合对象
 - 迭代器简化了聚合类
 - 在同一个聚合上可以有多个遍历
 
缺点:
- 由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性
 
17. 中介者模式 (Mediator)
概念:用一个中介对象来封装一系列对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散。
使用场景:
- 一组对象以定义良好但是复杂的方式进行通信
 - 想定制一个分布在多个类中的行为,而不想生成太多的子类
 
C++实现:
class Colleague;
class Mediator {
public:
    virtual ~Mediator() {}
    virtual void send(const std::string& message, Colleague* colleague) = 0;
};
class Colleague {
protected:
    Mediator* mediator_;
    std::string name_;
    
public:
    Colleague(Mediator* mediator, const std::string& name) 
        : mediator_(mediator), name_(name) {}
    
    virtual void send(const std::string& message) {
        mediator_->send(message, this);
    }
    
    virtual void receive(const std::string& message) {
        std::cout << name_ << " received: " << message << std::endl;
    }
    
    std::string getName() const { return name_; }
};
class ConcreteMediator : public Mediator {
private:
    std::vector<Colleague*> colleagues_;
    
public:
    void addColleague(Colleague* colleague) {
        colleagues_.push_back(colleague);
    }
    
    void send(const std::string& message, Colleague* sender) override {
        for (auto colleague : colleagues_) {
            if (colleague != sender) {
                colleague->receive(message);
            }
        }
    }
};
优点:
- 简化了对象之间的交互
 - 将各同事对象解耦
 - 减少子类生成
 
缺点:
- 中介者会庞大,变得复杂难以维护
 
18. 备忘录模式 (Memento)
概念:在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
使用场景:
- 需要保存和恢复数据的相关状态
 - 提供一个可回滚的操作
 - 需要监控对象的状态
 
C++实现:
// 备忘录
class Memento {
private:
    std::string state_;
    
public:
    Memento(const std::string& state) : state_(state) {}
    
    std::string getState() const { return state_; }
    void setState(const std::string& state) { state_ = state; }
};
// 原发器
class Originator {
private:
    std::string state_;
    
public:
    void setState(const std::string& state) {
        state_ = state;
        std::cout << "Originator: state set to " << state_ << std::endl;
    }
    
    std::string getState() const { return state_; }
    
    std::unique_ptr<Memento> saveStateToMemento() {
        return std::make_unique<Memento>(state_);
    }
    
    void getStateFromMemento(Memento* memento) {
        state_ = memento->getState();
        std::cout << "Originator: state restored to " << state_ << std::endl;
    }
};
// 管理者
class CareTaker {
private:
    std::vector<std::unique_ptr<Memento>> mementoList_;
    
public:
    void add(std::unique_ptr<Memento> state) {
        mementoList_.push_back(std::move(state));
    }
    
    Memento* get(int index) {
        return mementoList_[index].get();
    }
};
优点:
- 给用户提供了一种可以恢复状态的机制
 - 实现了信息的封装
 
缺点:
- 消耗资源
 - 如果状态数据很大,备忘录模式会非常消耗内存
 
19. 观察者模式 (Observer)
概念:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
使用场景:
- 一个对象的改变需要同时改变其他对象
 - 一个对象必须通知其他对象,而不知道这些对象是谁
 - 需要在系统中创建一个触发链
 
C++实现:
class Observer {
public:
    virtual ~Observer() {}
    virtual void update(const std::string& message) = 0;
};
class Subject {
public:
    virtual ~Subject() {}
    virtual void attach(Observer* observer) = 0;
    virtual void detach(Observer* observer) = 0;
    virtual void notify(const std::string& message) = 0;
};
class ConcreteSubject : public Subject {
private:
    std::list<Observer*> observers_;
    std::string state_;
    
public:
    void attach(Observer* observer) override {
        observers_.push_back(observer);
    }
    
    void detach(Observer* observer) override {
        observers_.remove(observer);
    }
    
    void notify(const std::string& message) override {
        for (auto observer : observers_) {
            observer->update(message);
        }
    }
    
    void setState(const std::string& state) {
        state_ = state;
        notify("State changed to: " + state_);
    }
    
    std::string getState() const { return state_; }
};
class ConcreteObserver : public Observer {
private:
    std::string name_;
    ConcreteSubject* subject_;
    
public:
    ConcreteObserver(const std::string& name, ConcreteSubject* subject) 
        : name_(name), subject_(subject) {}
    
    void update(const std::string& message) override {
        std::cout << name_ << " received update: " << message << std::endl;
    }
};
优点:
- 观察者和被观察者是抽象耦合的
 - 建立一套触发机制
 
缺点:
- 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间
 - 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃
 
20. 状态模式 (State)
概念:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
使用场景:
- 对象的行为依赖于它的状态
 - 需要在运行时根据状态改变行为
 - 操作中有大量的条件分支
 
C++实现:
class Context;
class State {
public:
    virtual ~State() {}
    virtual void handle(Context& context) = 0;
    virtual std::string getName() = 0;
};
class Context {
private:
    std::unique_ptr<State> state_;
    
public:
    Context(std::unique_ptr<State> state) : state_(std::move(state)) {}
    
    void setState(std::unique_ptr<State> state) {
        std::cout << "Context: Transitioning to " << state->getName() << std::endl;
        state_ = std::move(state);
    }
    
    void request() {
        state_->handle(*this);
    }
};
class ConcreteStateA : public State {
public:
    void handle(Context& context) override;
    std::string getName() override { return "StateA"; }
};
class ConcreteStateB : public State {
public:
    void handle(Context& context) override;
    std::string getName() override { return "StateB"; }
};
void ConcreteStateA::handle(Context& context) {
    std::cout << "StateA: handling request" << std::endl;
    context.setState(std::make_unique<ConcreteStateB>());
}
void ConcreteStateB::handle(Context& context) {
    std::cout << "StateB: handling request" << std::endl;
    context.setState(std::make_unique<ConcreteStateA>());
}
优点:
- 封装了转换规则
 - 枚举可能的状态,在枚举状态之前需要确定状态种类
 - 将所有与某个状态有关的行为放到一个类中
 
缺点:
- 状态模式的使用必然会增加系统类和对象的个数
 - 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱
 - 状态模式对"开闭原则"的支持并不太好
 
21. 策略模式 (Strategy)
概念:定义一系列算法,把它们一个个封装起来,并且使它们可以互相替换。
使用场景:
- 许多相关的类仅仅是行为有异
 - 需要使用一个算法的不同变体
 - 算法使用客户不应该知道的数据
 
C++实现:
class Strategy {
public:
    virtual ~Strategy() {}
    virtual void execute() = 0;
};
class ConcreteStrategyA : public Strategy {
public:
    void execute() override {
        std::cout << "Strategy A: sorting array" << std::endl;
    }
};
class ConcreteStrategyB : public Strategy {
public:
    void execute() override {
        std::cout << "Strategy B: reverse sorting array" << std::endl;
    }
};
class Context {
private:
    std::unique_ptr<Strategy> strategy_;
    
public:
    void setStrategy(std::unique_ptr<Strategy> strategy) {
        strategy_ = std::move(strategy);
    }
    
    void executeStrategy() {
        if (strategy_) {
            strategy_->execute();
        }
    }
};
优点:
- 算法可以自由切换
 - 避免使用多重条件判断
 - 扩展性良好
 
缺点:
- 策略类会增多
 - 所有策略类都需要对外暴露
 
22. 模板方法模式 (Template Method)
概念:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。
使用场景:
- 有多个子类共有的方法,且逻辑相同
 - 重要的、复杂的方法,可以考虑作为模板方法
 
C++实现:
class AbstractClass {
public:
    void templateMethod() {
        baseOperation1();
        requiredOperation1();
        baseOperation2();
        hook1();
        requiredOperation2();
        baseOperation3();
        hook2();
    }
    
protected:
    void baseOperation1() {
        std::cout << "AbstractClass: Base operation 1" << std::endl;
    }
    
    void baseOperation2() {
        std::cout << "AbstractClass: Base operation 2" << std::endl;
    }
    
    void baseOperation3() {
        std::cout << "AbstractClass: Base operation 3" << std::endl;
    }
    
    virtual void requiredOperation1() = 0;
    virtual void requiredOperation2() = 0;
    
    virtual void hook1() {}
    virtual void hook2() {}
};
class ConcreteClass1 : public AbstractClass {
protected:
    void requiredOperation1() override {
        std::cout << "ConcreteClass1: Required operation 1" << std::endl;
    }
    
    void requiredOperation2() override {
        std::cout << "ConcreteClass1: Required operation 2" << std::endl;
    }
    
    void hook1() override {
        std::cout << "ConcreteClass1: Hook 1" << std::endl;
    }
};
class ConcreteClass2 : public AbstractClass {
protected:
    void requiredOperation1() override {
        std::cout << "ConcreteClass2: Required operation 1" << std::endl;
    }
    
    void requiredOperation2() override {
        std::cout << "ConcreteClass2: Required operation 2" << std::endl;
    }
    
    void hook2() override {
        std::cout << "ConcreteClass2: Hook 2" << std::endl;
    }
};
优点:
- 封装不变部分,扩展可变部分
 - 提取公共代码,便于维护
 - 行为由父类控制,子类实现
 
缺点:
- 每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大
 
23. 访问者模式 (Visitor)
概念:封装一些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
使用场景:
- 对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作
 - 需要对一个对象结构中的对象进行很多不同的并且不相关的操作
 
C++实现:
class ConcreteElementA;
class ConcreteElementB;
class Visitor {
public:
    virtual ~Visitor() {}
    virtual void visit(ConcreteElementA& element) = 0;
    virtual void visit(ConcreteElementB& element) = 0;
};
class Element {
public:
    virtual ~Element() {}
    virtual void accept(Visitor& visitor) = 0;
};
class ConcreteElementA : public Element {
public:
    void accept(Visitor& visitor) override {
        visitor.visit(*this);
    }
    
    std::string operationA() const {
        return "ConcreteElementA";
    }
};
class ConcreteElementB : public Element {
public:
    void accept(Visitor& visitor) override {
        visitor.visit(*this);
    }
    
    std::string operationB() const {
        return "ConcreteElementB";
    }
};
class ConcreteVisitor1 : public Visitor {
public:
    void visit(ConcreteElementA& element) override {
        std::cout << "Visitor1: " << element.operationA() << std::endl;
    }
    
    void visit(ConcreteElementB& element) override {
        std::cout << "Visitor1: " << element.operationB() << std::endl;
    }
};
class ConcreteVisitor2 : public Visitor {
public:
    void visit(ConcreteElementA& element) override {
        std::cout << "Visitor2: " << element.operationA() << std::endl;
    }
    
    void visit(ConcreteElementB& element) override {
        std::cout << "Visitor2: " << element.operationB() << std::endl;
    }
};
优点:
- 符合单一职责原则
 - 优秀的扩展性
 - 灵活性
 
缺点:
- 具体元素对访问者公布细节,违反了迪米特原则
 - 具体元素变更比较困难
 - 违反了依赖倒置原则
 
实践应用
何时使用设计模式
✅ 适合使用的场景:
- 当遇到重复出现的设计问题时
 - 需要提高代码的可维护性和可扩展性时
 - 团队需要统一的代码结构和风格时
 - 需要解耦系统组件时
 - 需要支持未来的功能扩展时
 
❌ 不适合使用的场景:
- 过度使用设计模式
 - 不理解问题本质就盲目应用
 - 性能要求极高且模式带来额外开销
 - 简单的功能不需要复杂的设计
 
模式选择指南
创建型模式选择
| 场景 | 推荐模式 | 
|---|---|
| 只需要一个实例 | 单例模式 | 
| 需要创建产品族 | 抽象工厂 | 
| 需要逐步构建复杂对象 | 建造者模式 | 
| 需要复制现有对象 | 原型模式 | 
| 需要灵活创建单个产品 | 工厂方法 | 
结构型模式选择
| 场景 | 推荐模式 | 
|---|---|
| 接口不兼容 | 适配器模式 | 
| 需要分离抽象和实现 | 桥接模式 | 
| 需要树形结构 | 组合模式 | 
| 需要动态添加功能 | 装饰模式 | 
| 需要简化复杂接口 | 外观模式 | 
| 需要优化大量相似对象 | 享元模式 | 
| 需要控制对象访问 | 代理模式 | 
行为型模式选择
| 场景 | 推荐模式 | 
|---|---|
| 需要处理请求链 | 职责链模式 | 
| 需要支持撤销重做 | 命令模式 | 
| 需要解释简单语言 | 解释器模式 | 
| 需要遍历集合 | 迭代器模式 | 
| 需要解耦对象交互 | 中介者模式 | 
| 需要保存恢复状态 | 备忘录模式 | 
| 需要事件通知 | 观察者模式 | 
| 需要状态驱动行为 | 状态模式 | 
| 需要动态选择算法 | 策略模式 | 
| 需要定义算法骨架 | 模板方法 | 
| 需要操作对象结构 | 访问者模式 | 
最佳实践
- 
理解问题再选择模式
- 先分析问题本质
 - 确定是否真的需要设计模式
 - 选择最适合的模式
 
 - 
保持简单
- 不要为了使用模式而使用
 - 简单的解决方案通常更好
 - 考虑维护成本
 
 - 
组合使用模式
- 多个模式可以协同工作
 - 注意模式间的依赖关系
 - 避免过度设计
 
 - 
团队协作
- 确保团队成员理解设计
 - 统一编码规范
 - 定期代码审查
 
 
总结
设计模式是软件开发中的重要工具,它们提供了经过验证的解决方案来解决常见的设计问题。通过学习和应用这些模式,我们可以:
学到的技能
- 编写更可维护、可扩展的代码
 - 提高代码质量和可读性
 - 更好地理解面向对象设计原则
 - 在团队中建立共同的设计语言
 
学习建议
- 循序渐进 - 从简单的模式开始,逐步学习复杂的模式
 - 实践应用 - 在实际项目中尝试应用学到的模式
 - 理解原理 - 不仅要学会使用,更要理解背后的设计思想
 - 持续学习 - 设计模式是一个持续学习的过程
 
未来展望
- 学习更多的架构模式
 - 了解领域驱动设计 (DDD)
 - 掌握函数式编程模式
 - 关注新兴的设计思想和模式
 
设计模式不是银弹,它们是工具箱中的工具。正确地使用它们可以帮助我们构建更好的软件系统。记住,最好的设计是最简单、最清晰的设计。
参考资料
- 《设计模式:可复用面向对象软件的基础》 - Gang of Four
 - 《Head First 设计模式》 - Eric Freeman & Elisabeth Robson
 - 《大话设计模式》 - 程杰
 - Refactoring.Guru - https://refactoring.guru/design-patterns
 - SourceMaking - https://sourcemaking.com/design_patterns
 
希望这份指南能帮助你更好地理解和应用设计模式! Happy Coding! 🚀
                    
                
                
            
        
浙公网安备 33010602011771号