常用二十种设计模式


概述

C++中常用的设计模式有很多,设计模式是解决常见问题的经过验证的最佳实践。以下是一些常用的设计模式:

  1. 单例模式(Singleton):确保一个类只有一个实例,并提供一个全局访问点。
  2. 工厂模式(Factory):用于创建对象,而不需要指定具体类。
  3. 抽象工厂模式(Abstract Factory):提供一组相关或相互依赖的对象,而不指定其具体类。
  4. 建造者模式(Builder):将一个复杂对象的构建与其表示分离,使相同的构建过程可以创建不同的表示。
  5. 原型模式(Prototype):通过克隆已有对象来创建新对象,以避免直接使用构造函数。
  6. 适配器模式(Adapter):将一个接口转换成另一个客户希望使用的接口。
  7. 装饰器模式(Decorator):动态地给一个对象添加一些额外的职责,而不需要子类化。
  8. 代理模式(Proxy):为其他对象提供一个代理以控制对这个对象的访问。
  9. 观察者模式(Observer):定义了一种一对多的依赖关系,当一个对象状态改变时,所有依赖它的对象都会得到通知。
  10. 策略模式(Strategy):定义一系列算法,封装它们,使它们可以相互替换。
  11. 命令模式(Command):将一个请求封装成一个对象,从而允许使用不同的请求、队列或日志请求。
  12. 状态模式(State):允许对象在其内部状态改变时改变其行为。
  13. 模板方法模式(Template Method):定义算法的骨架,允许子类重写其中的步骤。
  14. 访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
  15. 组合模式(Composite):将对象组合成树形结构以表示“部分-整体”的层次结构。
  16. 迭代器模式(Iterator):提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。
  17. 中介者模式(Mediator):定义一个对象,封装一系列对象之间的交互,从而降低对象之间的耦合度。
  18. 备忘录模式(Memento):不破坏封装的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态。
  19. 桥接模式(Bridge):将抽象部分与它的实现部分分离,使它们可以独立变化。
  20. 解释器模式(Interpreter):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

1.单例模式

提供所有设计模式的 C++ 示例代码是一个庞大的任务,但我可以为您提供一个示例,演示如何使用 C++ 实现一个常见的设计模式——单例模式(Singleton)。

单例模式(Singleton) 确保一个类只有一个实例,并提供全局访问点。以下是一个基本的单例模式示例:

#include <iostream>

class Singleton {
public:
    static Singleton& getInstance() {
        static Singleton instance;  // 静态局部变量确保只初始化一次
        return instance;
    }

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

private:
    Singleton() {}  // 构造函数私有,只能通过 getInstance() 获取实例
};

int main() {
    // 获取 Singleton 实例
    Singleton& singleton = Singleton::getInstance();
    singleton.doSomething();

    return 0;
}

在这个示例中,Singleton 类的构造函数是私有的,这意味着外部无法直接创建 Singleton 对象。通过 getInstance() 静态成员函数,我们可以获取到单一的 Singleton 实例。这确保了只有一个实例存在。 单例模式常用于需要共享资源或控制访问某些全局状态的情况。在实际项目中,设计模式的选择会根据具体需求和架构决策,不同的模式可能会以不同的方式被实现和使用。

2.工厂模式

工厂模式(Factory Pattern)是一种创建型设计模式,用于创建对象而无需指定对象的具体类。工厂模式通过定义一个共同的接口,由不同的工厂子类来实现,并根据不同的情况返回不同的具体对象。

以下是一个简单的工厂模式的 C++ 示例:

#include <iostream>

// 抽象产品类
class Product {
public:
    virtual void use() = 0;
};

// 具体产品类 A
class ConcreteProductA : public Product {
public:
    void use() override {
        std::cout << "Product A in use." << std::endl;
    }
};

// 具体产品类 B
class ConcreteProductB : public Product {
public:
    void use() override {
        std::cout << "Product B in use." << std::endl;
    }
};

// 抽象工厂类
class Factory {
public:
    virtual Product* createProduct() = 0;
};

// 具体工厂类 A,用于创建 ProductA
class ConcreteFactoryA : public Factory {
public:
    Product* createProduct() override {
        return new ConcreteProductA();
    }
};

// 具体工厂类 B,用于创建 ProductB
class ConcreteFactoryB : public Factory {
public:
    Product* createProduct() override {
        return new ConcreteProductB();
    }
};

int main() {
    // 使用具体工厂类 A 创建产品 A
    Factory* factoryA = new ConcreteFactoryA();
    Product* productA = factoryA->createProduct();
    productA->use();

    // 使用具体工厂类 B 创建产品 B
    Factory* factoryB = new ConcreteFactoryB();
    Product* productB = factoryB->createProduct();
    productB->use();

    delete factoryA;
    delete factoryB;
    delete productA;
    delete productB;

    return 0;
}

在这个示例中,我们定义了抽象产品类 Product,有两个具体的产品类 ConcreteProductAConcreteProductB,它们都继承自 Product。然后,我们定义了抽象工厂类 Factory,有两个具体工厂类 ConcreteFactoryAConcreteFactoryB,它们分别负责创建不同的产品。

通过使用工厂模式,我们可以根据具体的需求选择不同的工厂类来创建产品,而无需关心产品的具体类是什么。这提供了灵活性,允许我们轻松扩展和替换具体产品和工厂类。

这是一个简单的示例,实际中工厂模式可用于更复杂的对象创建需求。工厂模式常用于创建对象的场景,特别是在代码中需要降低耦合性时非常有用。

3.抽象工厂模式

抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一个接口,用于创建一系列相关或依赖的对象,而不需要指定它们的具体类。抽象工厂模式的核心思想是为每个产品族(相关的一组产品)定义一个抽象工厂,然后在每个具体工厂中实现该抽象工厂。

以下是一个简单的抽象工厂模式的 C++ 示例:

#include <iostream>

// 抽象产品 A
class AbstractProductA {
public:
    virtual void useA() = 0;
};

// 具体产品 A1
class ConcreteProductA1 : public AbstractProductA {
public:
    void useA() override {
        std::cout << "Product A1 in use." << std::endl;
    }
};

// 具体产品 A2
class ConcreteProductA2 : public AbstractProductA {
public:
    void useA() override {
        std::cout << "Product A2 in use." << std::endl;
    }
};

// 抽象产品 B
class AbstractProductB {
public:
    virtual void useB() = 0;
};

// 具体产品 B1
class ConcreteProductB1 : public AbstractProductB {
public:
    void useB() override {
        std::cout << "Product B1 in use." << std::endl;
    }
};

// 具体产品 B2
class ConcreteProductB2 : public AbstractProductB {
public:
    void useB() override {
        std::cout << "Product B2 in use." << std::endl;
    }
};

// 抽象工厂
class AbstractFactory {
public:
    virtual AbstractProductA* createProductA() = 0;
    virtual AbstractProductB* createProductB() = 0;
};

// 具体工厂 1
class ConcreteFactory1 : public AbstractFactory {
public:
    AbstractProductA* createProductA() override {
        return new ConcreteProductA1();
    }

    AbstractProductB* createProductB() override {
        return new ConcreteProductB1();
    }
};

// 具体工厂 2
class ConcreteFactory2 : public AbstractFactory {
public:
    AbstractProductA* createProductA() override {
        return new ConcreteProductA2();
    }

    AbstractProductB* createProductB() override {
        return new ConcreteProductB2();
    }
};

int main() {
    // 使用具体工厂 1 创建产品 A 和 B
    AbstractFactory* factory1 = new ConcreteFactory1();
    AbstractProductA* productA1 = factory1->createProductA();
    AbstractProductB* productB1 = factory1->createProductB();

    productA1->useA();
    productB1->useB();

    // 使用具体工厂 2 创建产品 A 和 B
    AbstractFactory* factory2 = new ConcreteFactory2();
    AbstractProductA* productA2 = factory2->createProductA();
    AbstractProductB* productB2 = factory2->createProductB();

    productA2->useA();
    productB2->useB();

    delete factory1;
    delete productA1;
    delete productB1;

    delete factory2;
    delete productA2;
    delete productB2;

    return 0;
}

在这个示例中,我们定义了两个抽象产品类 AbstractProductAAbstractProductB,以及它们的具体实现类。然后,我们定义了抽象工厂类 AbstractFactory,它包括两个工厂方法,分别用于创建产品 A 和产品 B。具体工厂类 ConcreteFactory1ConcreteFactory2 分别实现了 AbstractFactory,用于创建不同的产品族。

抽象工厂模式允许我们在不知道具体产品类的情况下创建一组相关产品,这对于需要保持产品族之间的一致性非常有用。此模式还支持易于替换整个产品族,以满足不同的需求。

4.建造者模式

建造者模式(Builder Pattern)是一种创建型设计模式,用于构建一个复杂对象,将构造过程和表示分离。通常情况下,该模式包括一个 Director(指挥者)类、一个抽象 Builder(建造者)接口和具体的 Builder 实现类。

以下是一个简单的建造者模式的 C++ 示例:

#include <iostream>
#include <string>

// 产品类,即要构建的复杂对象
class Product {
public:
    void setPartA(const std::string& partA) {
        partA_ = partA;
    }

    void setPartB(const std::string& partB) {
        partB_ = partB;
    }

    void setPartC(const std::string& partC) {
        partC_ = partC;
    }

    void show() {
        std::cout << "Product parts: " << partA_ << ", " << partB_ << ", " << partC_ << std::endl;
    }

private:
    std::string partA_;
    std::string partB_;
    std::string partC_;
};

// 抽象 Builder 接口
class Builder {
public:
    virtual void buildPartA() = 0;
    virtual void buildPartB() = 0;
    virtual void buildPartC() = 0;
    virtual Product getResult() = 0;
};

// 具体 Builder 实现
class ConcreteBuilder : public Builder {
public:
    ConcreteBuilder() {
        product_ = new Product();
    }

    void buildPartA() override {
        product_->setPartA("Part A");
    }

    void buildPartB() override {
        product_->setPartB("Part B");
    }

    void buildPartC() override {
        product_->setPartC("Part C");
    }

    Product getResult() override {
        return *product_;
    }

private:
    Product* product_;
};

// 指挥者类,负责构建产品
class Director {
public:
    Director(Builder* builder) : builder_(builder) {}

    Product construct() {
        builder_->buildPartA();
        builder_->buildPartB();
        builder_->buildPartC();
        return builder_->getResult();
    }

private:
    Builder* builder_;
};

int main() {
    ConcreteBuilder builder;
    Director director(&builder);

    Product product = director.construct();
    product.show();

    return 0;
}

在这个示例中,我们有一个产品类 Product,包括三个部分。我们定义了抽象 Builder 接口,包括构建每个部分的方法和获取最终产品的方法。具体 Builder 类 ConcreteBuilder 实现了 Builder 接口,构建了 Product 的各个部分。指挥者类 Director 负责指导 Builder 构建产品。

使用建造者模式,我们可以按照不同的需求构建不同的产品,而不必关心构建的细节。这种模式尤其适用于构建复杂对象,帮助将构建过程和表示分离,提高了可维护性和可扩展性。

5.原型模式

原型模式(Prototype Pattern)是一种创建型设计模式,其主要思想是通过复制现有对象(原型)来创建新对象,而不需要从头开始构建。这种模式通常用于创建成本高昂或复杂的对象,同时可以保持对象的不变性。原型模式基于对象的克隆,可以分为浅拷贝和深拷贝两种。

以下是一个简单的原型模式的 C++ 示例:

#include <iostream>
#include <string>

// 原型类
class Prototype {
public:
    virtual Prototype* clone() = 0;
    virtual void print() = 0;
};

// 具体原型类 A
class ConcretePrototypeA : public Prototype {
public:
    Prototype* clone() override {
        return new ConcretePrototypeA(*this); // 深拷贝
    }

    void print() override {
        std::cout << "ConcretePrototypeA" << std::endl;
    }
};

// 具体原型类 B
class ConcretePrototypeB : public Prototype {
public:
    Prototype* clone() override {
        return new ConcretePrototypeB(*this); // 深拷贝
    }

    void print() override {
        std::cout << "ConcretePrototypeB" << std::endl;
    }
};

int main() {
    Prototype* originalA = new ConcretePrototypeA();
    Prototype* originalB = new ConcretePrototypeB();

    // 克隆原型对象
    Prototype* cloneA = originalA->clone();
    Prototype* cloneB = originalB->clone();

    originalA->print();
    cloneA->print();

    originalB->print();
    cloneB->print();

    delete originalA;
    delete cloneA;
    delete originalB;
    delete cloneB;

    return 0;
}

在这个示例中,我们定义了一个抽象原型类 Prototype,包括克隆方法 clone 和打印方法 print。然后,我们创建了两个具体的原型类 ConcretePrototypeAConcretePrototypeB,它们实现了克隆方法,并在打印方法中展示自己的类型。

main 函数中,我们首先创建原型对象 originalAoriginalB,然后通过调用它们的 clone 方法,创建了相应的克隆对象 cloneAcloneB。这些克隆对象与原型对象具有相同的状态,但是是独立的对象。

原型模式允许我们根据需要克隆对象,而不必重新创建。这对于创建成本高昂或复杂的对象,以及需要保持对象不变性的情况非常有用。需要注意的是,深拷贝和浅拷贝的选择取决于对象内部的状态和结构。在实际应用中,可能需要自定义克隆方法以适应特定需求。

6.适配器模式

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许一个类的接口与另一个类的接口兼容。适配器模式主要用于解决两个已有接口之间的不匹配问题,使它们可以一起工作,而不需要修改它们的源代码。

适配器模式有两种主要类型:类适配器和对象适配器。

类适配器 使用多重继承,它继承了被适配类并实现了目标接口。

对象适配器 维护一个被适配类的实例,并实现了目标接口,然后委托被适配类的实例来执行相应的操作。

以下是一个简单的对象适配器模式的 C++ 示例:

#include <iostream>

// 目标接口
class Target {
public:
    virtual void request() = 0;
};

// 被适配类
class Adaptee {
public:
    void specificRequest() {
        std::cout << "Adaptee's specific request." << std::endl;
    }
};

// 对象适配器
class Adapter : public Target {
public:
    Adapter(Adaptee* adaptee) : adaptee_(adaptee) {}

    void request() override {
        adaptee_->specificRequest();
    }

private:
    Adaptee* adaptee_;
};

int main() {
    Adaptee adaptee;
    Target* adapter = new Adapter(&adaptee);

    adapter->request();

    delete adapter;

    return 0;
}

在这个示例中,我们有一个目标接口 Target,包括 request 方法。我们还有一个被适配类 Adaptee,它包括 specificRequest 方法,但它的接口与 Target 不兼容。

然后,我们创建了一个对象适配器 Adapter,它实现了 Target 接口,并维护了一个 Adaptee 的实例。在 Adapterrequest 方法中,我们将调用委托给 AdapteespecificRequest 方法,从而使 Adaptee 可以与 Target 接口兼容。

适配器模式在现实中的应用非常广泛,特别是在将旧系统与新系统集成或者使用第三方库时,它可以起到很好的桥梁作用,以确保不同接口之间的兼容性。

类适配器

类适配器模式使用多重继承来实现适配,它继承了被适配类并实现了目标接口。以下是一个简单的类适配器模式的 C++ 示例:

#include <iostream>

// 目标接口
class Target {
public:
    virtual void request() = 0;
};

// 被适配类
class Adaptee {
public:
    void specificRequest() {
        std::cout << "Adaptee's specific request." << std::endl;
    }
};

// 类适配器,继承自 Adaptee 和实现 Target 接口
class Adapter : public Adaptee, public Target {
public:
    void request() override {
        specificRequest(); // 调用 Adaptee 的方法
    }
};

int main() {
    Target* adapter = new Adapter();

    adapter->request();

    delete adapter;

    return 0;
}

在这个示例中,我们有一个目标接口 Target,包括 request 方法。我们还有一个被适配类 Adaptee,它包括 specificRequest 方法,但它的接口与 Target 不兼容。

然后,我们创建了一个类适配器 Adapter,它继承自 Adaptee 并实现了 Target 接口。在 Adapterrequest 方法中,我们可以直接调用 specificRequest 方法,因为 Adapter 继承了 Adaptee

类适配器模式使用多重继承,这使得它可以同时继承多个类,但也可能引入一些复杂性。适配器模式可用于解决现有系统的接口不兼容问题,同时不需要修改被适配类的源代码。

7.装饰器模式

装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许你通过将对象包装在装饰器类的实例中来动态地扩展其行为,而不需要修改其源代码。装饰器模式通常用于以下情况:

  1. 动态地给对象添加功能,而不是静态继承;
  2. 需要遵循开放/封闭原则,即对扩展是开放的,对修改是封闭的;
  3. 需要通过一系列可重用的装饰器来组合不同的行为。

以下是一个简单的装饰器模式的 C++ 示例:

#include <iostream>

// 抽象组件接口
class Component {
public:
    virtual void operation() = 0;
};

// 具体组件
class ConcreteComponent : public Component {
public:
    void operation() override {
        std::cout << "ConcreteComponent operation." << std::endl;
    }
};

// 抽象装饰器
class Decorator : public Component {
public:
    Decorator(Component* component) : component_(component) {}

    void operation() override {
        component_->operation();
    }

private:
    Component* component_;
};

// 具体装饰器 A
class ConcreteDecoratorA : public Decorator {
public:
    ConcreteDecoratorA(Component* component) : Decorator(component) {}

    void operation() override {
        Decorator::operation();
        std::cout << "ConcreteDecoratorA operation." << std::endl;
    }
};

// 具体装饰器 B
class ConcreteDecoratorB : public Decorator {
public:
    ConcreteDecoratorB(Component* component) : Decorator(component) {}

    void operation() override {
        Decorator::operation();
        std::cout << "ConcreteDecoratorB operation." << std::endl;
    }
};

int main() {
    Component* component = new ConcreteComponent();
    Component* decoratorA = new ConcreteDecoratorA(component);
    Component* decoratorB = new ConcreteDecoratorB(decoratorA);

    component->operation();  // 基本组件操作
    decoratorA->operation(); // 增加了装饰器 A 的操作
    decoratorB->operation(); // 增加了装饰器 A 和装饰器 B 的操作

    delete component;
    delete decoratorA;
    delete decoratorB;

    return 0;
}

在这个示例中,我们有一个抽象组件接口 Component,包括 operation 方法。具体组件 ConcreteComponent 实现了这个接口。

然后,我们定义了抽象装饰器 Decorator,它也实现了 Component 接口,但在 operation 方法中调用了包装的组件的 operation 方法。具体装饰器类 ConcreteDecoratorAConcreteDecoratorB 扩展了 Decorator 类,分别增加了特定的操作。

main 函数中,我们创建了一个基本组件 component,然后依次用装饰器 decoratorAdecoratorB 包装它。通过这样的嵌套,我们可以动态地添加不同的行为,而不需要修改组件的源代码。

装饰器模式允许我们以一种灵活的方式组合对象,以满足不同需求。这可以帮助我们遵循开放/封闭原则,同时保持代码的可维护性和可扩展性。

8.代理模式

代理模式(Proxy Pattern)是一种结构型设计模式,它允许你提供一个代理类,控制对其他对象的访问。代理模式通常用于以下情况:

  1. 远程代理:代理对象控制对远程对象的访问,例如通过网络。
  2. 虚拟代理:代理对象控制对创建开销大的对象的访问,只在需要时创建。
  3. 保护代理:代理对象控制对对象的访问权限,用于权限控制等。
  4. 智能引用:代理对象添加额外的逻辑,例如引用计数、懒加载等。

以下是一个简单的代理模式的 C++ 示例:

#include <iostream>

// 抽象主题
class Subject {
public:
    virtual void request() = 0;
};

// 具体主题
class RealSubject : public Subject {
public:
    void request() override {
        std::cout << "RealSubject handles the request." << std::endl;
    }
};

// 代理
class Proxy : public Subject {
public:
    Proxy(Subject* realSubject) : realSubject_(realSubject) {}

    void request() override {
        if (checkAccess()) {
            realSubject_->request();
            logAccess();
        } else {
            std::cout << "Access denied." << std::endl;
        }
    }

private:
    bool checkAccess() {
        // 检查访问权限的逻辑
        return true;
    }

    void logAccess() {
        // 记录访问日志的逻辑
        std::cout << "Access logged." << std::endl;
    }

    Subject* realSubject_;
};

int main() {
    RealSubject realSubject;
    Proxy proxy(&realSubject);

    proxy.request();

    return 0;
}

在这个示例中,我们有一个抽象主题 Subject,包括 request 方法。具体主题 RealSubject 实现了这个接口,用于处理请求。

然后,我们创建了代理 Proxy,它也实现了 Subject 接口。在 Proxyrequest 方法中,我们可以添加额外的逻辑,例如检查访问权限和记录访问日志。如果权限检查通过,它将委托给实际主题 RealSubject 来处理请求。

代理模式使我们能够控制对对象的访问,同时可以添加各种额外的功能,例如权限控制、懒加载、缓存等。这对于保持代码的可维护性和可扩展性非常有帮助。

9.观察者模式

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,使一个对象的状态发生变化时,其所有依赖者(观察者)都会收到通知并自动更新。观察者模式通常用于以下情况:

  1. 当一个对象的状态变化需要通知其他对象,而且这些对象的数量和类型是未知的。
  2. 当一个对象需要在不知道具体操作的情况下通知其他对象。
  3. 当一个对象需要维护一系列依赖关系,以便在状态变化时能够通知所有依赖者。

观察者模式包含以下几个关键角色:

  1. 主题(Subject):主题是被观察的对象,它包含一组观察者对象,并提供方法来添加、删除和通知观察者。
  2. 观察者(Observer):观察者是接收主题通知的对象,它定义了更新方法,以便在主题状态发生变化时能够执行相应操作。

以下是一个简单的观察者模式的 C++ 示例:

#include <iostream>
#include <vector>

// 观察者接口
class Observer {
public:
    virtual void update(const std::string& message) = 0;
};

// 主题接口
class Subject {
public:
    virtual void addObserver(Observer* observer) = 0;
    virtual void removeObserver(Observer* observer) = 0;
    virtual void notifyObservers(const std::string& message) = 0;
};

// 具体观察者
class ConcreteObserver : public Observer {
public:
    ConcreteObserver(const std::string& name) : name_(name) {}

    void update(const std::string& message) override {
        std::cout << name_ << " received message: " << message << std::endl;
    }

private:
    std::string name_;
};

// 具体主题
class ConcreteSubject : public Subject {
public:
    void addObserver(Observer* observer) override {
        observers_.push_back(observer);
    }

    void removeObserver(Observer* observer) override {
        // 寻找并移除观察者
        auto it = std::find(observers_.begin(), observers_.end(), observer);
        if (it != observers_.end()) {
            observers_.erase(it);
        }
    }

    void notifyObservers(const std::string& message) override {
        for (Observer* observer : observers_) {
            observer->update(message);
        }
    }

private:
    std::vector<Observer*> observers_;
};

int main() {
    ConcreteSubject subject;
    ConcreteObserver observer1("Observer 1");
    ConcreteObserver observer2("Observer 2");

    subject.addObserver(&observer1);
    subject.addObserver(&observer2);

    subject.notifyObservers("Hello, observers!");

    subject.removeObserver(&observer1);

    subject.notifyObservers("Observers after removal.");

    return 0;
}

在这个示例中,我们定义了观察者接口 Observer 和主题接口 Subject,分别包括添加、移除和通知观察者的方法。然后,我们创建了具体的观察者类 ConcreteObserver 和具体的主题类 ConcreteSubject

main 函数中,我们创建主题对象 subject 和两个观察者对象 observer1observer2。我们将观察者添加到主题中,然后主题通知观察者时,它们会接收到消息并执行相应的操作。

观察者模式使对象之间的关系松散,允许主题和观察者之间的独立变化,同时保持了对象之间的协作。这种模式常用于实现事件处理、发布-订阅系统以及任何需要实现对象之间松耦合通信的情况。

10.策略模式

策略模式(Strategy Pattern)是一种行为型设计模式,它允许定义一系列算法,并将每个算法封装到独立的策略类中,使这些算法可以互相替换。策略模式的核心思想是将算法的选择与使用分离,从而实现更灵活的算法切换,同时不需要修改上下文类的代码。

策略模式包含以下几个主要角色:

  1. 上下文(Context):上下文类包含一个策略接口的引用,它可以在运行时切换不同的策略对象,以实现不同的行为。上下文类不直接实现算法,而是将算法委托给策略对象。
  2. 策略(Strategy):策略是一个接口或抽象类,定义了一个算法族的接口,具体的策略类实现了这个接口,每个策略类代表一个具体的算法。

使用策略模式的主要优点包括:

  • 算法的可独立替换性:可以在运行时切换算法,而不需要修改上下文类的代码。
  • 降低了上下文类的复杂性:上下文类只需要关注如何选择和使用策略,而不需要实现具体算法。
  • 提高了代码的可维护性和可扩展性:每个策略类可以独立开发和测试,容易新增新的策略。

以下是一个简单的策略模式的 C++ 示例:

#include <iostream>

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

// 具体策略 A
class ConcreteStrategyA : public Strategy {
public:
    void doOperation() override {
        std::cout << "Using Strategy A" << std::endl;
    }
};

// 具体策略 B
class ConcreteStrategyB : public Strategy {
public:
    void doOperation() override {
        std::cout << "Using Strategy B" << std::endl;
    }
};

// 上下文
class Context {
public:
    Context(Strategy* strategy) : strategy_(strategy) {}

    void setStrategy(Strategy* strategy) {
        strategy_ = strategy;
    }

    void executeStrategy() {
        strategy_->doOperation();
    }

private:
    Strategy* strategy_;
};

int main() {
    ConcreteStrategyA strategyA;
    ConcreteStrategyB strategyB;

    Context context(&strategyA);
    context.executeStrategy();

    context.setStrategy(&strategyB);
    context.executeStrategy();

    return 0;
}

在这个示例中,我们有一个策略接口 Strategy,定义了算法族的接口。然后,我们创建了两个具体策略类 ConcreteStrategyAConcreteStrategyB,分别实现了不同的算法。

上下文类 Context 包含一个策略对象的引用,它可以在运行时切换不同的策略。当调用 executeStrategy 方法时,上下文类会委托策略对象执行相应的算法。

策略模式的应用范围很广,可以用于任何需要动态地选择算法的场景,例如排序算法、计算费用、路由策略等。

11.命令模式

命令模式(Command Pattern)是一种行为型设计模式,它将请求封装成一个对象,从而允许你参数化不同的请求、将请求排队、记录请求日志,或者支持可撤销的操作。命令模式的核心思想是将请求的发送者与请求的接收者解耦。

命令模式包含以下几个主要角色:

  1. 命令(Command):命令是一个抽象类或接口,它定义了执行请求的方法 execute。具体的命令类将实现这个接口,将请求参数绑定到接收者,并在 execute 方法中执行具体的操作。
  2. 具体命令(Concrete Command):具体命令是命令接口的具体实现,它包括一个接收者对象,负责执行具体的操作。
  3. 接收者(Receiver):接收者是具体命令类的执行者,它包含了具体的业务逻辑,命令类将请求委派给接收者来执行。
  4. 调用者(Invoker):调用者是负责向命令对象发送请求的对象,它不需要了解命令是如何执行的,只需要将请求发送给命令对象。

命令模式的主要优点包括:

  • 解耦命令发送者和命令执行者。
  • 支持撤销和重做操作。
  • 支持命令的组合,可以构建复杂的命令序列。

以下是一个简单的命令模式的 C++ 示例:

#include <iostream>

// 命令接口
class Command {
public:
    virtual void execute() = 0;
};

// 具体命令
class LightOnCommand : public Command {
public:
    LightOnCommand(Light& light) : light_(light) {}

    void execute() override {
        light_.on();
    }

private:
    Light& light_;
};

// 接收者
class Light {
public:
    void on() {
        std::cout << "Light is on" << std::endl;
    }

    void off() {
        std::cout << "Light is off" << std::endl;
    }
};

// 调用者
class RemoteControl {
public:
    void setCommand(Command* command) {
        command_ = command;
    }

    void pressButton() {
        command_->execute();
    }

private:
    Command* command_;
};

int main() {
    Light livingRoomLight;
    LightOnCommand livingRoomLightOn(livingRoomLight);

    RemoteControl remote;
    remote.setCommand(&livingRoomLightOn);
    remote.pressButton();

    return 0;
}

在这个示例中,我们有一个命令接口 Command,定义了 execute 方法。具体命令 LightOnCommand 包含一个接收者对象 Light,在 execute 方法中调用接收者的方法。

调用者 RemoteControl 通过设置具体命令对象,并调用 pressButton 方法来执行命令。这种方式实现了调用者和接收者的解耦,调用者只需要知道如何发送命令,而不需要知道命令是如何执行的。

命令模式非常适用于构建可扩展和可维护的系统,特别是需要支持撤销、重做和构建复杂命令序列的情况。

12.状态模式

状态模式(State Pattern)是一种行为型设计模式,它允许对象在其内部状态改变时改变其行为。状态模式的核心思想是将不同状态抽象为独立的状态类,使对象能够在运行时切换不同状态,而不需要修改其代码。

状态模式包含以下几个主要角色:

  1. 上下文(Context):上下文类是包含状态的对象,它在运行时可以切换不同的状态对象。上下文类通常包括状态接口的引用,用于与当前状态进行交互。
  2. 状态(State):状态是一个抽象类或接口,它定义了一个特定状态的行为。具体的状态类将实现这个接口,每个状态类代表一个具体的状态,并定义了状态下的行为。

状态模式的主要优点包括:

  • 将状态的行为封装在独立的状态类中,降低了上下文类的复杂性。
  • 支持动态切换状态,使对象能够在运行时改变行为。
  • 易于添加新的状态,同时不需要修改现有代码。

以下是一个简单的状态模式的 C++ 示例:

#include <iostream>

// 状态接口
class State {
public:
    virtual void handle() = 0;
};

// 具体状态 A
class ConcreteStateA : public State {
public:
    void handle() override {
        std::cout << "Handling state A" << std::endl;
    }
};

// 具体状态 B
class ConcreteStateB : public State {
public:
    void handle() override {
        std::cout << "Handling state B" << std::endl;
    }
};

// 上下文
class Context {
public:
    void setState(State* state) {
        state_ = state;
    }

    void request() {
        state_->handle();
    }

private:
    State* state_;
};

int main() {
    ConcreteStateA stateA;
    ConcreteStateB stateB;

    Context context;

    context.setState(&stateA);
    context.request();

    context.setState(&stateB);
    context.request();

    return 0;
}

在这个示例中,我们有一个状态接口 State,定义了 handle 方法,具体状态类 ConcreteStateAConcreteStateB 分别实现了这个接口。

上下的 Context 包含一个状态对象的引用,它可以在运行时切换不同的状态。当调用 request 方法时,上下文对象会委托给当前状态对象来执行特定的行为。

状态模式使对象能够根据内部状态的改变而改变行为,这有助于消除大量的条件分支,提高了代码的可维护性和可扩展性。状态模式常用于处理对象的状态机、有限状态机、工作流等场景。

13.模板方法模式

模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一组算法的骨架,将一些步骤延迟到子类实现。模板方法模式允许子类在不改变算法结构的情况下重新定义算法的某些步骤。

模板方法模式包含以下几个主要角色:

  1. 模板方法(Template Method):模板方法是一个抽象类,它定义了一个算法的骨架,包括一组步骤,其中一些步骤由子类实现。
  2. 具体模板(Concrete Template):具体模板类是模板方法的具体实现,它实现了模板方法中定义的具体步骤,其中一些步骤可能由子类实现。

模板方法模式的主要特点包括:

  • 定义了一个算法的骨架,其中一些步骤延迟到子类实现。
  • 子类可以重新定义模板方法中的特定步骤,以满足其特定需求,而无需改变算法的整体结构。
  • 模板方法模式使得代码重用和扩展变得更加容易。

以下是一个简单的模板方法模式的 C++ 示例:

#include <iostream>

// 模板方法
class AbstractClass {
public:
    // 模板方法定义了算法的骨架,包括一组步骤
    void templateMethod() {
        step1();
        step2();
        step3();
    }

    // 具体步骤由子类实现
    virtual void step1() = 0;
    virtual void step2() = 0;
    virtual void step3() = 0;
};

// 具体模板
class ConcreteClassA : public AbstractClass {
public:
    void step1() override {
        std::cout << "ConcreteClassA - Step 1" << std::endl;
    }

    void step2() override {
        std::cout << "ConcreteClassA - Step 2" << std::endl;
    }

    void step3() override {
        std::cout << "ConcreteClassA - Step 3" << std::endl;
    }
};

class ConcreteClassB : public AbstractClass {
public:
    void step1() override {
        std::cout << "ConcreteClassB - Step 1" << std::endl;
    }

    void step2() override {
        std::cout << "ConcreteClassB - Step 2" << std::endl;
    }

    void step3() override {
        std::cout << "ConcreteClassB - Step 3" << std::endl;
    }
};

int main() {
    ConcreteClassA a;
    ConcreteClassB b;

    a.templateMethod();
    b.templateMethod();

    return 0;
}

在这个示例中,我们有一个抽象类 AbstractClass,它定义了一个模板方法 templateMethod,包括一组步骤(step1step2step3)。具体的步骤由子类实现。具体子类 ConcreteClassAConcreteClassB 分别实现了这些步骤。

当我们调用 templateMethod 时,模板方法会按照定义的算法骨架执行各个步骤。不同的子类可以重新定义这些步骤,以满足其特定需求。

模板方法模式非常适用于需要定义算法骨架但允许某些步骤由子类自定义的情况,例如,创建框架、工作流程或其他多步骤的操作。这有助于提高代码的可复用性和可维护性。

14.访问者模式(Visitor)

访问者模式(Visitor Pattern)是一种行为型设计模式,它用于分离数据结构和数据操作,并允许在不修改数据结构的情况下添加新的操作。访问者模式的核心思想是将数据结构和操作分离,使得数据结构可以在不同的操作下表现不同的行为。

访问者模式包含以下几个主要角色:

  1. 访问者(Visitor):访问者是一个抽象类或接口,它定义了一组访问操作,每个操作对应一个具体的元素类型。
  2. 具体访问者(Concrete Visitor):具体访问者是访问者接口的具体实现,每个具体访问者实现了一组具体的访问操作。
  3. 元素(Element):元素是一个抽象类或接口,它定义了一个 accept 方法,该方法接受一个访问者对象作为参数,允许访问者访问该元素。
  4. 具体元素(Concrete Element):具体元素是元素接口的具体实现,每个具体元素实现了 accept 方法,用于调用访问者的相应操作。
  5. 对象结构(Object Structure):对象结构是一个包含多个元素的集合,它通常提供一个接受访问者的方法,用于遍历元素并调用访问者的操作。

访问者模式的主要优点包括:

  • 分离了数据结构和数据操作,使得可以添加新的操作而无需修改现有数据结构。
  • 支持对数据结构进行不同的操作,从而提供更多的灵活性和扩展性。
  • 使得数据结构可以遵循开闭原则(Open/Closed Principle),即对扩展开放,对修改关闭。

以下是一个简单的访问者模式的 C++ 示例:

#include <iostream>
#include <vector>

// 前向声明,让元素类知道访问者类
class Visitor;

// 元素接口
class Element {
public:
    virtual void accept(Visitor& visitor) = 0;
};

// 具体元素 A
class ConcreteElementA : public Element {
public:
    void accept(Visitor& visitor) override {
        visitor.visitElementA(*this);
    }

    void operationA() {
        std::cout << "Operation A on ConcreteElementA" << std::endl;
    }
};

// 具体元素 B
class ConcreteElementB : public Element {
public:
    void accept(Visitor& visitor) override {
        visitor.visitElementB(*this);
    }

    void operationB() {
        std::cout << "Operation B on ConcreteElementB" << std::endl;
    }
};

// 访问者接口
class Visitor {
public:
    virtual void visitElementA(ConcreteElementA& element) = 0;
    virtual void visitElementB(ConcreteElementB& element) = 0;
};

// 具体访问者
class ConcreteVisitor : public Visitor {
public:
    void visitElementA(ConcreteElementA& element) override {
        element.operationA();
    }

    void visitElementB(ConcreteElementB& element) override {
        element.operationB();
    }
};

int main() {
    ConcreteElementA elementA;
    ConcreteElementB elementB;
    ConcreteVisitor visitor;

    elementA.accept(visitor);
    elementB.accept(visitor);

    return 0;
}

在这个示例中,我们有两种具体元素 ConcreteElementAConcreteElementB,它们都实现了元素接口,并提供了 accept 方法,以允许访问者访问这些元素。

具体访问者 ConcreteVisitor 实现了访问者接口中定义的访问操作,其中包括操作 A 和操作 B。

通过访问者模式,我们可以在不修改元素类的情况下,为元素类添加新的操作(在这个示例中是操作 A 和操作 B)。这种分离数据结构和操作的设计模式使得代码更加灵活和可维护。

15.组合模式(Composite)

组合模式(Composite Pattern)是一种结构型设计模式,用于将对象组合成树状结构以表示“部分-整体”的层次结构。组合模式允许客户端以一致的方式处理单个对象和对象组合。

组合模式包含以下几个主要角色:

  1. 组件(Component):组件是一个抽象类或接口,它声明了管理子组件的方法,以及其他操作的接口。
  2. 叶子(Leaf):叶子是组件的具体实现,它表示树结构中的叶子节点,不包含子组件。
  3. 容器(Composite):容器是组件的具体实现,它表示树结构中的分支节点,可以包含子组件。容器类通常会实现管理子组件的方法。

组合模式的主要优点包括:

  • 客户端可以以一致的方式处理单个对象和对象组合,无需知道具体组件的类型。
  • 可以递归地构建复杂的对象结构,使代码具有更高的可扩展性。
  • 通过组合模式,可以更容易地添加新的组件类型。

以下是一个简单的组合模式的 C++ 示例:

#include <iostream>
#include <vector>

// 抽象组件
class Component {
public:
    virtual void operation() = 0;
};

// 叶子组件
class Leaf : public Component {
public:
    void operation() override {
        std::cout << "Leaf operation" << std::endl;
    }
};

// 容器组件
class Composite : public Component {
public:
    void operation() override {
        std::cout << "Composite operation" << std::endl;

        // 调用子组件的操作
        for (Component* child : children_) {
            child->operation();
        }
    }

    void add(Component* component) {
        children_.push_back(component);
    }

private:
    std::vector<Component*> children_;
};

int main() {
    Leaf leaf1, leaf2;
    Composite composite;

    composite.add(&leaf1);
    composite.add(&leaf2);

    composite.operation();

    return 0;
}

在这个示例中,我们有一个抽象组件 Component,包括一个操作方法 operationLeaf 类是叶子组件,它是组件的具体实现,而 Composite 类是容器组件,它可以包含多个子组件。

main 函数中,我们创建了两个叶子组件和一个容器组件,并将叶子组件添加到容器组件中。当调用容器组件的 operation 方法时,它会递归调用其子组件的 operation 方法,从而实现了整体-部分的层次结构。

组合模式常用于处理树状结构,例如文件系统、图形界面控件、组织架构等情况,其中可以递归地组合和管理各种对象。

16.迭代器模式

迭代器模式(Iterator Pattern)是一种行为型设计模式,用于提供一种访问聚合对象中各个元素的方法,而无需暴露聚合对象的内部表示。迭代器模式将遍历聚合对象的操作封装在一个迭代器对象中,使客户端能够以一致的方式遍历不同类型的聚合对象。

迭代器模式包含以下几个主要角色:

  1. 迭代器(Iterator):迭代器是一个抽象接口,它定义了用于遍历聚合对象的方法,包括移动到下一个元素、检查是否还有元素等操作。
  2. 具体迭代器(Concrete Iterator):具体迭代器是迭代器接口的具体实现,它实现了在特定聚合对象上的遍历方法。
  3. 聚合(Aggregate):聚合是一个抽象接口,它定义了用于创建迭代器的方法。
  4. 具体聚合(Concrete Aggregate):具体聚合是聚合接口的具体实现,它包含了一组元素,可以生成相应的具体迭代器。

迭代器模式的主要优点包括:

  • 客户端可以通过迭代器以一致的方式遍历不同类型的聚合对象,无需关心具体的数据结构。
  • 迭代器模式将遍历操作封装在独立的迭代器对象中,使聚合对象的结构保持私有,提高了封装性。
  • 支持多种迭代方式,例如正向遍历、反向遍历、跳跃式遍历等。

以下是一个简单的迭代器模式的 C++ 示例:

#include <iostream>
#include <vector>

// 抽象迭代器
class Iterator {
public:
    virtual int next() = 0;
    virtual bool hasNext() = 0;
};

// 具体迭代器
class ConcreteIterator : public Iterator {
public:
    ConcreteIterator(const std::vector<int>& collection) : collection_(collection), index_(0) {}

    int next() override {
        return collection_[index_++];
    }

    bool hasNext() override {
        return index_ < collection_.size();
    }

private:
    std::vector<int> collection_;
    int index_;
};

// 抽象聚合
class Aggregate {
public:
    virtual Iterator* createIterator() = 0;
};

// 具体聚合
class ConcreteAggregate : public Aggregate {
public:
    ConcreteAggregate(const std::vector<int>& collection) : collection_(collection) {}

    Iterator* createIterator() override {
        return new ConcreteIterator(collection_);
    }

private:
    std::vector<int> collection_;
};

int main() {
    std::vector<int> data = {1, 2, 3, 4, 5};
    ConcreteAggregate aggregate(data);
    Iterator* iterator = aggregate.createIterator();

    while (iterator->hasNext()) {
        std::cout << iterator->next() << " ";
    }

    delete iterator;

    return 0;
}

在这个示例中,我们有一个抽象迭代器 Iterator,具体迭代器 ConcreteIterator,抽象聚合 Aggregate,以及具体聚合 ConcreteAggregate

具体聚合 ConcreteAggregate 包含了一组整数元素,并提供了创建迭代器的方法。具体迭代器 ConcreteIterator 实现了在集合上的遍历操作。

main 函数中,我们创建了一个包含整数的聚合对象,然后创建了一个迭代器对象,通过迭代器以一致的方式遍历聚合中的元素。这种设计模式使得客户端可以在不关心聚合内部结构的情况下进行遍历操作。

17.中介者模式(Mediator)

中介者模式(Mediator Pattern)是一种行为型设计模式,它用于减少对象之间的直接通信,将对象间的交互通过一个中介者对象进行协调和控制。中介者模式有助于降低系统中对象之间的耦合度,使系统更易维护和扩展。

中介者模式包含以下几个主要角色:

  1. 中介者(Mediator):中介者是一个接口或抽象类,它定义了对象之间交互的方法,包括注册、通知、协调等。
  2. 具体中介者(Concrete Mediator):具体中介者是中介者接口的具体实现,它协调各个相关对象之间的交互,并维护对象之间的引用。
  3. 同事类(Colleague):同事类是相互交互的对象,它们通过中介者来进行通信,而不直接依赖其他同事类。

中介者模式的主要优点包括:

  • 降低了对象之间的直接耦合,使系统更加灵活和可维护。
  • 可以集中控制对象之间的交互,使系统的交互逻辑更清晰。
  • 支持新增和删除同事类,对系统扩展更加友好。

以下是一个简单的中介者模式的 C++ 示例:

#include <iostream>
#include <string>

// 抽象中介者
class Mediator {
public:
    virtual void sendMessage(const std::string& message, class Colleague* colleague) = 0;
};

// 具体中介者
class ConcreteMediator : public Mediator {
public:
    void sendMessage(const std::string& message, class Colleague* colleague) override {
        std::cout << "Message from " << colleague->getName() << ": " << message << std::endl;
    }
};

// 同事类
class Colleague {
public:
    Colleague(const std::string& name, Mediator* mediator) : name_(name), mediator_(mediator) {}

    void sendMessage(const std::string& message) {
        mediator_->sendMessage(message, this);
    }

    const std::string& getName() {
        return name_;
    }

private:
    std::string name_;
    Mediator* mediator_;
};

int main() {
    ConcreteMediator mediator;
    Colleague colleague1("Colleague 1", &mediator);
    Colleague colleague2("Colleague 2", &mediator);

    colleague1.sendMessage("Hello from Colleague 1");
    colleague2.sendMessage("Hi from Colleague 2");

    return 0;
}

在这个示例中,我们有一个抽象中介者 Mediator,具体中介者 ConcreteMediator,以及两个同事类 Colleague。同事类通过中介者来发送消息,而不直接与其他同事类进行通信。

中介者模式在协调对象之间的交互时非常有用,特别是在大型系统中,当对象之间的交互关系复杂时,可以通过引入中介者来简化和集中控制交互逻辑。这有助于减少系统的复杂性和提高可维护性。

18.备忘录模式(Memento)

备忘录模式(Memento Pattern)是一种行为型设计模式,它用于捕获一个对象的内部状态,并将其保存在一个外部对象中,从而可以在以后将对象恢复到先前的状态。备忘录模式的关键思想是在不破坏封装性的前提下,将对象的状态保存和恢复。

备忘录模式包含以下几个主要角色:

  1. 发起人(Originator):发起人是需要保存状态的对象。它有一个创建备忘录和恢复备忘录的方法。发起人的状态可能会变化,可以使用备忘录来保存不同时间点的状态。
  2. 备忘录(Memento):备忘录是保存发起人状态的对象。它包含了发起人在某一时刻的状态信息。
  3. 管理者(Caretaker):管理者是用于保存和管理备忘录的对象。它可以保存多个备忘录,以便在需要时恢复发起人的状态。

备忘录模式的主要优点包括:

  • 允许在不破坏封装性的情况下保存对象的状态,从而可以实现状态的撤销和恢复操作。
  • 提供了一种简单的方式来保存和管理对象的历史状态,支持多次撤销操作。
  • 可以降低发起人对象的复杂性,因为状态保存和恢复的逻辑由备忘录和管理者处理。

以下是一个简单的备忘录模式的 C++ 示例:

#include <iostream>
#include <string>

// 备忘录类
class Memento {
public:
    Memento(const std::string& state) : state_(state) {}

    const std::string& getState() {
        return state_;
    }

private:
    std::string state_;
};

// 发起人类
class Originator {
public:
    void setState(const std::string& state) {
        state_ = state;
    }

    const std::string& getState() {
        return state_;
    }

    Memento createMemento() {
        return Memento(state_);
    }

    void restoreMemento(const Memento& memento) {
        state_ = memento.getState();
    }

private:
    std::string state_;
};

// 管理者类
class Caretaker {
public:
    void saveMemento(const Memento& memento) {
        mementos_.push_back(memento);
    }

    Memento getMemento(int index) {
        if (index >= 0 && index < mementos_.size()) {
            return mementos_[index];
        }
        // 返回一个空的备忘录以示错误
        return Memento("");
    }

private:
    std::vector<Memento> mementos_;
};

int main() {
    Originator originator;
    Caretaker caretaker;

    // 设置初始状态并保存备忘录
    originator.setState("State 1");
    caretaker.saveMemento(originator.createMemento());

    // 修改状态并保存备忘录
    originator.setState("State 2");
    caretaker.saveMemento(originator.createMemento());

    // 恢复到第一个备忘录状态
    originator.restoreMemento(caretaker.getMemento(0));
    std::cout << "Current state: " << originator.getState() << std::endl;

    return 0;
}

在这个示例中,Originator 类表示发起人,它有一个状态需要保存。Memento 类表示备忘录,它可以保存发起人的状态。Caretaker 类表示管理者,它可以保存和管理备忘录。

main 函数中,我们设置了初始状态,并保存了备忘录。然后,修改状态并再次保存备忘录。最后,我们恢复到第一个备忘录状态,从而实现了状态的撤销和恢复操作。备忘录模式非常有用,特别是在需要实现撤销和恢复功能的应用中。

19.桥接模式

桥接模式(Bridge Pattern)是一种结构型设计模式,它用于将抽象部分与实现部分分离,以便它们可以独立地变化。桥接模式的目的是将继承关系转化为组合关系,从而减少类之间的耦合度,提高系统的可扩展性。

桥接模式包含以下几个主要角色:

  1. 抽象部分(Abstraction):抽象部分定义了对实现部分的接口,它维护一个对实现部分的引用,并可以通过委托给实现部分来完成具体的操作。
  2. 扩展抽象部分(Refined Abstraction):扩展抽象部分是对抽象部分的扩展,通常会增加一些额外的操作。
  3. 实现部分(Implementor):实现部分定义了具体操作的接口,它可以是一个抽象类或接口,也可以是具体类。
  4. 具体实现部分(Concrete Implementor):具体实现部分是实现部分的具体实现,它实现了实现部分定义的接口。

桥接模式的主要优点包括:

  • 分离抽象部分和实现部分,使它们可以独立变化,增加了系统的灵活性。
  • 对于不同的抽象部分,可以选择不同的实现部分,从而实现了多样化的组合。
  • 提高了系统的可扩展性,新的抽象部分和实现部分可以方便地添加。

以下是一个简单的桥接模式的 C++ 示例:

#include <iostream>

// 实现部分接口
class Implementor {
public:
    virtual void operationImpl() = 0;
};

// 具体实现部分 A
class ConcreteImplementorA : public Implementor {
public:
    void operationImpl() override {
        std::cout << "Concrete Implementor A operation" << std::endl;
    }
};

// 具体实现部分 B
class ConcreteImplementorB : public Implementor {
public:
    void operationImpl() override {
        std::cout << "Concrete Implementor B operation" << std::endl;
    }
};

// 抽象部分
class Abstraction {
public:
    Abstraction(Implementor* implementor) : implementor_(implementor) {}

    virtual void operation() {
        implementor_->operationImpl();
    }

private:
    Implementor* implementor_;
};

// 扩展抽象部分
class RefinedAbstraction : public Abstraction {
public:
    RefinedAbstraction(Implementor* implementor) : Abstraction(implementor) {}

    void additionalOperation() {
        std::cout << "Additional operation" << std::endl;
    }
};

int main() {
    Implementor* implA = new ConcreteImplementorA();
    Implementor* implB = new ConcreteImplementorB();

    Abstraction* abstraction1 = new Abstraction(implA);
    abstraction1->operation();

    Abstraction* abstraction2 = new RefinedAbstraction(implB);
    abstraction2->operation();
    static_cast<RefinedAbstraction*>(abstraction2)->additionalOperation();

    delete implA;
    delete implB;
    delete abstraction1;
    delete abstraction2;

    return 0;
}

在这个示例中,我们有两个实现部分:ConcreteImplementorAConcreteImplementorB,它们实现了 Implementor 接口。然后,我们有抽象部分 Abstraction 和扩展抽象部分 RefinedAbstraction,它们使用实现部分来完成操作。

main 函数中,我们创建了两个不同的实现部分,然后分别将它们与抽象部分和扩展抽象部分组合。通过这种方式,我们可以轻松地改变抽象部分和实现部分的组合,实现不同的操作。这是桥接模式的典型应用。

20.解释器模式(Interpreter)

解释器模式(Interpreter Pattern)是一种行为型设计模式,它用于定义一种语言的文法规则,并提供一个解释器来解释语言中的表达式。该模式将一个句子(语法)分解成一系列的解释动作。解释器模式常用于编译器、解析器和领域特定语言的实现中。

解释器模式包含以下几个主要角色:

  1. 抽象表达式(Abstract Expression):抽象表达式定义了解释器的接口,包含一个 interpret 方法用于解释表达式。
  2. 终结符表达式(Terminal Expression):终结符表达式是继承自抽象表达式的类,它实现了 interpret 方法用于解释终结符表达式。
  3. 非终结符表达式(Non-terminal Expression):非终结符表达式也是继承自抽象表达式的类,它通常包含多个子表达式,并实现了 interpret 方法用于解释非终结符表达式。
  4. 上下文(Context):上下文包含要解释的文法规则的信息,通常包含解释器所需的数据。
  5. 客户端(Client):客户端创建并配置解释器,然后使用解释器来解释表达式。

解释器模式的主要优点是可以扩展语言的语法,以及在一些特定领域中解决问题。然而,它也有一些缺点,例如对于复杂的文法规则,解释器模式可能会变得复杂,难以维护。

以下是一个简单的解释器模式的 C++ 示例:

#include <iostream>
#include <unordered_map>

// 抽象表达式
class Expression {
public:
    virtual int interpret(std::unordered_map<char, int>& context) = 0;
};

// 终结符表达式
class TerminalExpression : public Expression {
public:
    TerminalExpression(char variable) : variable_(variable) {}

    int interpret(std::unordered_map<char, int>& context) override {
        return context[variable_];
    }

private:
    char variable_;
};

// 非终结符表达式
class NonterminalExpression : public Expression {
public:
    NonterminalExpression(Expression* left, Expression* right) : left_(left), right_(right) {}

    int interpret(std::unordered_map<char, int>& context) override {
        return left_->interpret(context) + right_->interpret(context);
    }

private:
    Expression* left_;
    Expression* right_;
};

int main() {
    std::unordered_map<char, int> context;
    context['a'] = 5;
    context['b'] = 10;

    Expression* expression = new NonterminalExpression(
        new TerminalExpression('a'),
        new TerminalExpression('b')
    );

    int result = expression->interpret(context);

    std::cout << "Result: " << result << std::endl;

    delete expression;

    return 0;
}

在这个示例中,我们创建了一个简单的表达式语言,包括终结符表达式和非终结符表达式。通过解释器模式,我们可以解释这些表达式并计算结果。这个示例是解释器模式的一个简单演示,实际应用中可能会涉及更复杂的语法和解释器。

总结

设计模式是一种通用的解决问题的模板或蓝图,它们用于解决特定类型的问题,并为软件设计提供了可重用的解决方案。在计算机科学中,有23种广泛接受的经典设计模式,它们通常被分为以下几个类别:

  1. 创建型模式(Creational Patterns):这些模式关注对象的创建机制,以便以适当的方式创建对象,隐藏创建的细节。创建型模式包括:
  • 单例模式(Singleton Pattern)
  • 工厂模式(Factory Pattern)
  • 抽象工厂模式(Abstract Factory Pattern)
  • 建造者模式(Builder Pattern)
  • 原型模式(Prototype Pattern)

结构型模式(Structural Patterns):这些模式处理对象之间的组合,以便形成更大的结构。结构型模式包括:

  • 适配器模式(Adapter Pattern)
  • 桥接模式(Bridge Pattern)
  • 组合模式(Composite Pattern)
  • 装饰器模式(Decorator Pattern)
  • 外观模式(Facade Pattern)
  • 享元模式(Flyweight Pattern)
  • 代理模式(Proxy Pattern)

行为型模式(Behavioral Patterns):这些模式关注对象之间的通信、职责分配和协作。行为型模式包括:

  • 责任链模式(Chain of Responsibility Pattern)
  • 命令模式(Command Pattern)
  • 解释器模式(Interpreter Pattern)
  • 迭代器模式(Iterator Pattern)
  • 中介者模式(Mediator Pattern)
  • 备忘录模式(Memento Pattern)
  • 观察者模式(Observer Pattern)
  • 状态模式(State Pattern)
  • 策略模式(Strategy Pattern)
  • 模板方法模式(Template Method Pattern)
  • 访问者模式(Visitor Pattern)

这些经典的设计模式提供了在特定情况下解决问题的有效方法,它们有助于提高软件的可维护性、可扩展性和可重用性。根据应用场景和需求,开发人员可以选择适当的设计模式来构建更健壮、可维护和可扩展的软件系统。


评论
  目录