当前位置: 首页 > news >正文

常用的二十种设计模式(上)-C++

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 创建产品 AFactory* factoryA = new ConcreteFactoryA();Product* productA = factoryA->createProduct();productA->use();// 使用具体工厂类 B 创建产品 BFactory* 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 和 BAbstractFactory* factory1 = new ConcreteFactory1();AbstractProductA* productA1 = factory1->createProductA();AbstractProductB* productB1 = factory1->createProductB();productA1->useA();productB1->useB();// 使用具体工厂 2 创建产品 A 和 BAbstractFactory* 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 方法时,上下文类会委托策略对象执行相应的算法。

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

相关文章:

常用的二十种设计模式(上)-C++

C中常用的设计模式有很多&#xff0c;设计模式是解决常见问题的经过验证的最佳实践。以下是一些常用的设计模式&#xff1a; 单例模式&#xff08;Singleton&#xff09;&#xff1a;确保一个类只有一个实例&#xff0c;并提供一个全局访问点。工厂模式&#xff08;Factory&am…...

JS中var和let和const的区别

在我很早之前&#xff0c;我还在用着var&#xff0c;直到接触到了let与const&#xff0c;我才知道var造成的影响很多&#xff0c;我果断的抛弃了var&#xff0c;哈哈 让我为大家介绍一下它们的区别吧&#xff01; 1.块级作用域 块作用域由 { }包括&#xff0c;let和const具有…...

如何利用IP定位技术进行反欺诈?

网络欺诈风险是指在互联网和数字领域中&#xff0c;存在各种类型的欺诈活动&#xff0c;旨在欺骗个人、组织或系统以获得非法获益。以下是一些常见的网络欺诈风险类型&#xff1a; 身份盗用&#xff1a;这是一种欺诈行为&#xff0c;涉及盗取他人的个人身份信息&#xff0c;如姓…...

wireshark抓包本地IDEA xml格式报文教程以及postman调用接口

1、选择 2、筛选...

MySQL学习(六)——视图和触发器

文章目录 1. 视图1.1 视图语法1.2 检查选项1.3 视图的更新1.4 视图的作用 2. 触发器2.1 介绍2.2 语法介绍2.3 触发器示例2.3.1 插入数据触发器2.3.2 修改数据触发器2.3.3 删除数据触发器 1. 视图 视图&#xff08;View&#xff09;是一种虚拟存在的表。视图中的数据并不在数据…...

那些你面试必须知道的ES6知识点

目录 1、var、let、const的区别2、作用域考题3、合并两个对象4、箭头函数和普通函数的区别5、Promise有几种状态6、find和filter的区别7、some和every的区别 1、var、let、const的区别 区别一&#xff1a; var有变量提升&#xff0c;而let和const没有 <script>console.l…...

AD9371 系列快速入口

参考资料&#xff1a; AD9371 JESD204 Interface Framework Generic JESD204B block designs AD9371 & AD9375 Prototyping Platform User Guide ADI™ Reference Designs HDL User Guide 相关设备 &#xff1a; ZCU106ADRV9371CPRO33-30.726 dB 衰减 AD9371ZCU102 移植到…...

Jenkins+vue发布项目

在Jenkins 中先创建一个任务名称 然后进行下一步&#xff0c;放一个项目 填写一些参数 参数1&#xff1a; 参数2&#xff1a; 参数3&#xff1a;参数4&#xff1a; 点击保存就行了 配置脚本 // git def git_url http://gitlab.xxxx.git def git_auth_id GITEE_RIVER…...

RSTP详解:对比STP,到底改进了什么?

一、RSTP概述 IEEE 802.1W中定义的RSTP可以视为STP的改进版本&#xff0c;RSTP在许多方面对STP进行了优化&#xff0c;它的收敛速度更快&#xff0c;而且能够兼容STP。 二、RSTP对STP的改进 改进点1&#xff1a;端口角色 、 改进点2&#xff1a;端口状态 RSTP的状态规范缩…...

从0到1,申请cos服务器并上传图片到cos文件服务器

目录 准备工作 Java代码编写 控制台打印 整理成工具类 编写接口 Postman测试 准备工作 1.进入网址腾讯云 产业智变云启未来 - 腾讯 (tencent.com) 2.搜索cos,点击立即使用&#xff0c;刚开始会免费赠送你 3.存储都是基于桶的&#xff0c;先创建桶&#xff0c;在桶里面创…...

Stm32_标准库_15_串口蓝牙模块_手机与蓝牙模块通信_BUG修复

代码&#xff1a; #include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "Serial.h" #include "Time.h" #include "Function.h" #include <stdio.h> #include <…...

文心一言帮忙写代码之微信小程序图片移动顺序

先上效果图&#xff0c;图片顺序可移动&#xff0c;左移右移调准顺序。 代码是文心一言帮忙写的&#xff0c;自己稍微改造就可以用了。 首先是往左移&#xff0c;也就是从下标1移到下标0 &#xff0c;下标2移到下标1 var imglist [‘aa’, ‘bb’, ‘cc’, ‘dd’]; function…...

【电子通识】USB接口三大类型图册

基本概念 不同时期的USB接口有不同的类型&#xff0c;USB接口分为插头和插座&#xff1a; 插头&#xff0c;plug&#xff0c;对应的也叫公口&#xff0c;即插别人的。 插座&#xff0c;receptacle&#xff0c;对应也叫做母口&#xff0c;即被插的。 USB的接口类型&#xff0…...

@Controller与@RestController

总结 Controller &#xff1a;定义一个控制器类. RequestMapping &#xff1a;给出外界访问方法的路径&#xff0c;或者说触发路径 &#xff0c;触发条件。 具体解析访问路径到某个方法上. ResponseBody &#xff1a;标记Controller类中的方法。把return的结果变成JSON对象…...

Compose Desktop 使用中的几个问题(分平台加载资源、编写Gradle 任务下载平台资源、桌面特有组件、鼠标键盘事件)

前言 在我之前的文章 Compose For Desktop 实践&#xff1a;使用 Compose-jb 做一个时间水印助手 中&#xff0c;我们使用 Compose For Desktop 写了一个用于读取照片 EXIF 中的拍摄日期参数并以文字水印的方式添加到照片上的桌面程序。 但是事实上&#xff0c;这个程序的名字…...

【华为OD机试python】返回矩阵中非1的元素个数【2023 B卷|200分】

【华为OD机试】-真题 !!点这里!! 【华为OD机试】真题考点分类 !!点这里 !! 题目描述 存在一个m*n的二维数组,其成员取值范围为0,1,2。 其中值为1的元素具备同化特性,每经过1S,将上下左右值为0的元素同化为1。 而值为2的元素,免疫同化。 将数组所有成员随机初始化为0或…...

容器安全 - 利用容器的特权配置实现对Kubernetes容器的攻击

《OpenShift / RHEL / DevSecOps 汇总目录》 文章目录 准备环境利用特权配置对Kubernetes容器攻击privileged hostpathprivileged hostpidprivilegedhostpathhostpidhostipchostnetwork 参考 通过将运行 Pod 的 privileged 设为 true&#xff0c;容器就以特权模式运行在宿主…...

深度剖析Android Binder IPC机制

Android系统的成功离不开其强大的IPC&#xff08;Inter-Process Communication&#xff09;机制&#xff0c;其中最引人注目的就是Binder。本文将深入探讨Binder的技术原理&#xff0c;解释其工作方式以及相关的关键概念。 什么是Binder Binder是Android系统中的IPC机制&…...

【底层服务/编程功底系列】「大数据算法体系」带你深入分析MapReduce算法 — Shuffle的执行过程

【底层服务/编程功底系列】「大数据算法体系」带你深入分析MapReduce算法 — Shuffle的执行过程 Shuffle是什么Shuffle的流程处理map任务的执行流程reduce任务的执行流程 Shuffle过程分析和优化map任务深入分析细化步骤分析1. 数据分片读取2. 分配计算Reduce服务Partitioner分区…...

CISA 彻底改变了恶意软件信息共享:网络安全的突破

在现代网络安全中&#xff0c;战术技术和程序&#xff08;TTP&#xff09;的共享对于防范网络事件至关重要。 因此&#xff0c;了解攻击向量和攻击类型之间的关联如今是让其他公司从其他公司遭受的 IT 事件中受益&#xff08;吸取经验教训&#xff09;的重要一步。 美国主要网…...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端&#xff0c;它允许HTTP与Elasticsearch 集群通信&#xff0c;而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...