六种常用设计模式

news2024/10/7 4:35:11

单例设计模式

单例模式指在整个系统生命周期里,保证一个类只能产生一个实例,确保该类的唯一性。

单例模式分类

单例模式可以分为懒汉式和饿汉式,两者之间的区别在于创建实例的时间不同:

  • 懒汉式:指系统运行中,实例并不存在,只有当需要使用该实例时,才会去创建并使用实例。(这种方式要考虑线程安全)
  • 饿汉式:指系统一运行,就初始化创建实例,当需要时,直接调用即可。(本身就线程安全,没有多线程的问题)

单例类特点

  • 构造函数和析构函数为private类型,目的禁止外部构造和析构
  • 拷贝构造和赋值运算符重载函数为private类型,目的是禁止外部拷贝和赋值,确保实例的唯一性

单例类的结构

  • 一个public的获取指向唯一的实例对象的指针的函数GetInstance()
  • 构造函数析构函数设为private,禁止外部构造和析构
  • 拷贝构造和赋值操作符重载函数设为private类型,禁止外部拷贝和赋值,确保实例的唯一性
  • 一个private的static的指向唯一的实例对象的指针

代码实现

//线程安全的懒汉模式
class singleClass {
public:
	
	static singleClass* getinstance()
	{//双重锁模式
		if (instance == nullptr)
		{//先判断是否为空,如果为空则进入,不为空说明已经存在实例,直接返回
            //进入后加锁
			i_mutex.lock();
			if (instance == nullptr)
			{//再判断一次,确保不会因为加锁期间多个线程同时进入
				instance = new singleClass();
			}
			i_mutex.unlock();//解锁
		}
		return instance;
	}
private:
    static singleClass* instance;
	static mutex i_mutex;//锁
	singleClass(){}
    singleClass(const singleClass& sc) {}//拷贝构造函数也需要设置为私有
};
singleClass* singleClass::instance=nullptr;
mutex singleClass::i_mutex;//类外初始化
//饿汉模式:不管用不用得到,都构造出来。本身就是线程安全的
class ehsingleClass {
public:
	static ehsingleClass* getinstance()
	{
		return instance;
	}
 
private:
    static ehsingleClass* instance;//静态成员变量必须类外初始化,只有一个
	ehsingleClass() {};
    ehsingleClass(const ehsingleClass& sc) {}//拷贝构造函数也需要设置为私有
};
ehsingleClass* ehsingleClass::instance = new ehsingleClass();
//类外定义,main开始执行前,该对象就存在了

工厂设计模式

工厂模式概念

工厂模式是一种创建型设计模式,它提供了一种封装对象创建过程的方式,从而使得客户端代码与创建具体对象的过程解耦合。

工厂模式主要包含以下几种变体:

  1. 简单工厂模式(Simple Factory Pattern):简单工厂模式通过一个工厂类来创建对象,客户端通过调用工厂类的静态方法或非静态方法来获取所需的对象实例。这种模式不符合开闭原则,因为每次新增产品都需要修改工厂类。

  2. 工厂方法模式(Factory Method Pattern):工厂方法模式将对象的创建委托给子类来完成。定义一个创建对象的接口,但让子类决定实例化哪个类。这种模式遵循了开闭原则,因为可以通过添加新的子类来扩展系统功能。

  3. 抽象工厂模式(Abstract Factory Pattern):抽象工厂模式提供了一个接口,用于创建相关或依赖对象的家族,而不需要指定具体的类。它是工厂方法模式的扩展,通过定义多个工厂接口来创建一系列相关对象。

工厂模式的核心思想是将对象的创建过程封装起来,使得客户端代码不需要直接依赖于具体对象的创建过程,而是依赖于工厂接口或方法来获取所需的对象实例。这样可以降低代码的耦合度,提高系统的灵活性和可维护性。

工厂模式适用于以下情况:

  • 当一个类不知道它必须创建的对象的类时。
  • 当一个类希望由其子类来指定所创建的对象时。
  • 当需要将对象的创建和使用分离时,以便更好地组织代码结构和逻辑关系。

1. 简单工厂模式(Simple Factory Pattern)

#include <iostream>

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

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

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

// 简单工厂类
class SimpleFactory {
public:
    static Product* createProduct(char type) {
        switch (type) {
            case 'A':
                return new ConcreteProductA();
            case 'B':
                return new ConcreteProductB();
            default:
                return nullptr;
        }
    }
};

int main() {
    // 创建具体产品对象
    Product* productA = SimpleFactory::createProduct('A');
    Product* productB = SimpleFactory::createProduct('B');

    // 调用具体产品对象的方法
    if (productA) productA->operation();
    if (productB) productB->operation();

    // 释放资源
    delete productA;
    delete productB;

    return 0;
}

2. 工厂方法模式(Factory Method Pattern)

#include <iostream>

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

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

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

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

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

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

int main() {
    // 创建具体工厂对象
    Factory* factoryA = new ConcreteFactoryA();
    Factory* factoryB = new ConcreteFactoryB();

    // 创建具体产品对象
    Product* productA = factoryA->createProduct();
    Product* productB = factoryB->createProduct();

    // 调用具体产品对象的方法
    if (productA) productA->operation();
    if (productB) productB->operation();

    // 释放资源
    delete factoryA;
    delete factoryB;
    delete productA;
    delete productB;

    return 0;
}

3. 抽象工厂模式(Abstract Factory Pattern)

#include <iostream>

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

// 具体产品类A1
class ConcreteProductA1 : public AbstractProductA {
public:
    void operationA() override {
        std::cout << "ConcreteProductA1: operationA()" << std::endl;
    }
};

// 具体产品类A2
class ConcreteProductA2 : public AbstractProductA {
public:
    void operationA() override {
        std::cout << "ConcreteProductA2: operationA()" << std::endl;
    }
};

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

// 具体产品类B1
class ConcreteProductB1 : public AbstractProductB {
public:
    void operationB() override {
        std::cout << "ConcreteProductB1: operationB()" << std::endl;
    }
};

// 具体产品类B2
class ConcreteProductB2 : public AbstractProductB {
public:
    void operationB() override {
        std::cout << "ConcreteProductB2: operationB()" << std::endl;
    }
};

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

// 具体工厂类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() {
    // 创建具体工厂对象
    AbstractFactory* factory1 = new ConcreteFactory1();
    AbstractFactory* factory2 = new ConcreteFactory2();

    // 创建具体产品对象
    AbstractProductA* productA1 = factory1->createProductA();
    AbstractProductB* productB1 = factory1->createProductB();
    AbstractProductA* productA2 = factory2->createProductA();
    AbstractProductB* productB2 = factory2->createProductB();

    // 调用具体产品对象的方法
    if (productA1) productA1->operationA();
    if (productB1) productB1->operationB();
    if (productA2) productA2->operationA();
    if (productB2) productB2->operationB();

    // 释放资源
    delete factory1;
    delete factory2;
    delete productA1;
    delete productB1;
    delete productA2;
    delete productB2;

    return 0;
}

抽象工厂模式(Abstract Factory Pattern)和工厂方法模式(Factory Method Pattern)都属于工厂模式的范畴,但它们之间有一些关键区别:

  1. 目的

    • 抽象工厂模式旨在提供一个接口,用于创建一系列相关或依赖对象的家族,而不需要指定具体的类。
    • 工厂方法模式旨在将对象的创建委托给子类来完成。它定义一个创建对象的接口,但让子类决定实例化哪个类。
  2. 结构

    • 抽象工厂模式通常由一个抽象工厂接口和多个具体工厂类组成。每个具体工厂类负责创建一个产品家族的产品。
    • 工厂方法模式通常由一个抽象产品类和一个抽象工厂类组成。抽象工厂类定义了创建产品的方法,具体工厂类负责实现这些方法来创建具体产品。
  3. 扩展

    • 抽象工厂模式通过添加新的具体工厂类来扩展系统,每个具体工厂类负责创建一个产品家族的产品。
    • 工厂方法模式通过添加新的具体工厂类或扩展现有的抽象工厂类来扩展系统,每个具体工厂类负责创建一个具体产品。
  4. 关系

    • 抽象工厂模式通常与工厂方法模式结合使用,一个抽象工厂类中可以包含多个工厂方法,每个工厂方法负责创建一个具体产品。
    • 工厂方法模式是抽象工厂模式的一个特例,它将抽象工厂类中的工厂方法设计成抽象的,然后由具体子类来实现。

观察者模式

观察者模式(Observer Pattern)

观察者模式(Observer Pattern)是一种行为设计模式,它定义了一种一对多的依赖关系,让多个观察者对象监听一个主题对象,当主题对象的状态发生变化时,所有依赖于它的观察者都会收到通知并自动更新。

在观察者模式中,有三个关键角色:

  1. Subject(主题):也称为被观察者或可观察对象,它是一个抽象类或接口,定义了被观察者需要实现的方法。主题对象维护一个观察者列表,并提供方法来注册、移除和通知观察者。

  2. Observer(观察者):也称为订阅者或监听者,它是一个抽象类或接口,定义了观察者需要实现的方法。观察者对象通过订阅主题对象来接收状态变化的通知,并执行相应的操作。

  3. ConcreteSubject(具体主题):是主题对象的具体实现类,它继承或实现了主题接口,并维护了一个状态变量。当状态变量发生变化时,具体主题对象会通知所有注册的观察者。

  4. ConcreteObserver(具体观察者):是观察者对象的具体实现类,它继承或实现了观察者接口,并定义了在接收到主题对象通知时所需要执行的操作。

观察者模式的优点包括:

  • 松耦合:主题对象和观察者对象之间是松耦合的,它们之间没有直接的依赖关系,可以独立地进行修改和扩展。
  • 可重用性:可以在不同的主题和观察者之间进行重复使用,使得代码更加灵活和可维护。
  • 多态性:可以通过继承和接口实现多态性,从而可以根据需要定义不同类型的主题和观察者。

观察者模式适用于以下情况:

  • 当一个对象的状态变化需要通知其他对象,并且不知道有多少个对象需要通知时。
  • 当一个对象的状态变化需要通知其他对象,但不希望这些对象与之耦合时。
  • 当一个对象的状态变化会导致其他对象的行为发生变化时。

工作流程:

观察者模式的工作流程通常涉及以下几个步骤:

  1. 定义主题接口:首先,需要定义一个主题接口或抽象类,其中包含了注册、移除和通知观察者的方法。这个接口或抽象类定义了主题对象的基本行为。

  2. 定义观察者接口:然后,需要定义一个观察者接口或抽象类,其中包含了接收通知并进行相应操作的方法。这个接口或抽象类定义了观察者的基本行为。

  3. 创建具体主题类:接着,创建一个具体主题类,实现主题接口,并维护一个观察者列表。具体主题类通常包含一个状态变量,当状态变化时会通知所有注册的观察者。

  4. 创建具体观察者类:然后,创建一个或多个具体观察者类,实现观察者接口,并定义在接收到主题对象通知时所需要执行的操作。每个具体观察者类通常包含一个指向具体主题对象的引用。

  5. 注册观察者:在需要订阅主题对象的观察者处,将具体观察者对象注册到具体主题对象的观察者列表中。

  6. 状态变化通知:当具体主题对象的状态发生变化时,调用通知方法,遍历观察者列表,并依次通知每个观察者对象。

  7. 观察者响应:每个观察者对象在接收到通知后,会执行相应的操作,根据具体业务需求进行处理。

  8. 取消注册观察者(可选):如果观察者不再对主题对象的状态变化感兴趣,可以取消注册观察者,将其从观察者列表中移除

代码实现

#include <iostream>
#include <vector>

// 定义观察者接口
class Observer {
public:
    virtual void update(int data) = 0;
    virtual ~Observer() {}
};

// 定义具体观察者类
class ConcreteObserver : public Observer {
public:
    void update(int data) override {
        std::cout << "ConcreteObserver received update: " << data << std::endl;
    }
};

// 定义主题接口
class Subject {
public:
    virtual void attach(Observer* observer) = 0;
    virtual void detach(Observer* observer) = 0;
    virtual void notify(int data) = 0;
    virtual ~Subject() {}
};

// 定义具体主题类
class ConcreteSubject : public Subject {
public:
    void attach(Observer* observer) override {
        observers.push_back(observer);
    }

    void detach(Observer* observer) override {
        auto it = std::find(observers.begin(), observers.end(), observer);
        if (it != observers.end()) {
            observers.erase(it);
        }
    }

    void notify(int data) override {
        for (Observer* observer : observers) {
            observer->update(data);
        }
    }

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

int main() {
    // 创建具体主题对象
    ConcreteSubject subject;

    // 创建具体观察者对象
    ConcreteObserver observer1;
    ConcreteObserver observer2;

    // 注册观察者
    subject.attach(&observer1);
    subject.attach(&observer2);

    // 发送通知
    subject.notify(123);

    // 移除观察者
    subject.detach(&observer1);

    // 再次发送通知
    subject.notify(456);

    return 0;
}

代理模式

代理模式(Proxy Pattern)

代理模式(Proxy Pattern)是一种结构型设计模式,它允许你提供一个代理对象来控制对其他对象的访问。代理对象通常充当客户端和目标对象之间的中间人,客户端通过代理对象间接访问目标对象,从而可以在访问过程中添加额外的功能,如延迟加载、访问控制、缓存等。

在代理模式中,通常有三个角色:

  1. Subject(抽象主题):定义了目标对象和代理对象共同实现的接口,它可以是抽象类或接口。抽象主题可以是真实主题和代理对象的共同接口,也可以是真实主题的接口。

  2. RealSubject(真实主题):定义了真实对象的具体实现,是代理模式中的核心对象。客户端最终想要访问的对象就是真实主题。

  3. Proxy(代理):实现了抽象主题接口,并维护一个指向真实主题的引用。代理对象在执行目标对象方法的同时,可以在方法执行前后添加额外的逻辑。

代理模式的优点包括:

  • 控制访问:可以通过代理对象来控制对真实对象的访问,如权限控制、审计等。
  • 增加功能:可以在不改变目标对象的前提下,通过代理对象为目标对象增加额外的功能,如缓存、延迟加载、日志记录等。
  • 保护目标对象:可以对真实对象进行保护,防止客户端直接访问,从而提高系统的安全性。

代理模式适用于以下情况:

  • 当需要在访问一个对象时添加额外的功能,但又不想修改原有的代码时。
  • 当需要对访问进行控制和保护时,如权限控制、审计等。
  • 当需要在访问一个远程对象或昂贵对象时进行性能优化,如延迟加载、缓存等。

代码实现

#include <iostream>

// 定义抽象主题接口
class Subject {
public:
    virtual void request() = 0;
    virtual ~Subject() {}
};

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

// 定义代理类
class Proxy : public Subject {
public:
    Proxy(Subject* realSubject) : realSubject(realSubject) {}

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

private:
    Subject* realSubject;

    bool checkAccess() {
        // 检查访问权限的逻辑
        std::cout << "Proxy: Checking access..." << std::endl;
        return true; // 简单起见,这里直接返回 true
    }

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

int main() {
    // 创建真实主题对象
    RealSubject* realSubject = new RealSubject();

    // 创建代理对象,并将真实主题对象传入代理对象的构造函数中
    Proxy* proxy = new Proxy(realSubject);

    // 通过代理对象访问真实主题对象的方法
    proxy->request();

    // 释放资源
    delete proxy;
    delete realSubject;

    return 0;
}

装饰器模式

装饰器模式(Decorator Pattern)

装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许你通过将对象放入包装器中来动态地扩展其行为。装饰器模式提供了一种灵活的方式来添加功能,而无需修改现有的代码。

在装饰器模式中,有四个关键角色:

  1. Component(组件):是一个抽象类或者接口,定义了被装饰对象和装饰器共同遵循的协议或契约。它可以是抽象类或接口,定义了具体组件和装饰器必须实现的操作。

  2. Concrete Component(具体组件):是实现了组件接口的具体对象。具体组件是被装饰的对象,它定义了基本行为,可以通过装饰器来扩展。

  3. Decorator(装饰器):是一个抽象类,实现了组件接口,并包含一个对组件对象的引用。装饰器可以根据需要对组件对象进行包装,以扩展其行为。

  4. Concrete Decorator(具体装饰器):是实现了装饰器接口的具体对象。具体装饰器包装了具体组件对象,并在其基础上添加额外的行为或功能。

装饰器模式的工作流程:

  1. 定义组件接口:首先,定义一个组件接口或抽象类,它声明了被装饰对象和装饰器共同遵循的协议或契约。组件接口通常包含一个或多个方法,用于定义组件的基本行为。

  2. 实现具体组件类:根据组件接口,创建一个具体的组件类,实现组件接口中定义的方法。具体组件类是被装饰的对象,它定义了基本行为,是装饰器模式的核心。

  3. 创建装饰器抽象类:定义一个装饰器抽象类,它实现了组件接口,并包含一个对组件对象的引用。装饰器抽象类提供了一个统一的接口,用于包装组件对象并在其基础上添加额外的功能。

  4. 实现具体装饰器类:根据装饰器抽象类,创建具体的装饰器类,实现装饰器抽象类中定义的方法。具体装饰器类可以根据需要在组件对象的基础上添加额外的行为或功能,从而扩展组件的功能。

  5. 创建装饰器链:根据业务需求,可以将多个装饰器对象按照一定的顺序组合成一个装饰器链。装饰器链中的每个装饰器对象都包装了一个组件对象,并可以在其基础上添加额外的功能。

  6. 使用装饰器模式:在客户端代码中,根据需要创建具体组件对象,并根据业务需求创建相应的装饰器对象,并将其按照一定的顺序组合成装饰器链。然后通过调用装饰器链的方法来执行操作,装饰器链会根据其包装的组件对象的类型以及装饰器对象的顺序依次执行相应的功能。

代码实现:

#include <iostream>

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

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

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

    void operation()  {
        if (component != nullptr) {
            component->operation();
        }
    }

protected:
    Component* component;
};

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

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

    void addBehavior() {
        std::cout << "ConcreteDecoratorA: addBehavior()" << std::endl;
    }
};

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

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

    void addBehavior() {
        std::cout << "ConcreteDecoratorB: addBehavior()" << std::endl;
    }
};

int main() {
    // 创建具体组件对象
    Component* component = new ConcreteComponent();

    // 创建具体装饰器A,并包装具体组件对象
    Decorator* decoratorA = new ConcreteDecoratorA(component);

    // 创建具体装饰器B,并包装具体装饰器A
    Decorator* decoratorB = new ConcreteDecoratorB(decoratorA);

    // 执行操作
    decoratorB->operation();

    // 释放资源
    delete decoratorB;
    delete decoratorA;
    delete component;

    return 0;
}

策略模式

策略模式(Strategy Pattern)

策略模式(Strategy Pattern)是一种行为设计模式,它定义了一系列算法,并使得这些算法可以相互替换,使得客户端在使用算法时可以独立于其具体实现。策略模式将算法的定义、使用和实现分离开来,使得每个算法可以独立变化而不影响其他部分。

在策略模式中,有三个关键角色:

  1. Context(上下文):上下文是策略模式的核心类,它包含了一个策略接口的引用,并在运行时根据具体的情况选择合适的算法来执行。上下文类通常提供一个设置策略的方法,以及一个执行策略的方法。

  2. Strategy(策略):策略是一个接口或抽象类,它定义了一系列算法的共同接口。具体的策略类实现了策略接口,并提供了具体的算法实现。

  3. ConcreteStrategy(具体策略):具体策略是策略模式的具体实现类,它实现了策略接口,并提供了具体的算法实现。

策略模式的优点包括:

  • 分离算法:将算法的定义、使用和实现分离开来,使得每个算法可以独立变化而不影响其他部分。
  • 扩展性:增加新的算法非常方便,只需要实现新的策略类,并在上下文中设置即可。
  • 复用性:策略模式使得算法可以在不同的上下文中共享和重复使用。

策略模式适用于以下情况:

  • 当一个类有多种行为,且需要在运行时根据具体情况选择合适的行为时。
  • 当一个类的行为可以通过组合不同的算法来实现,并且这些算法可以相互替换时。
  • 当一个类的行为在不同的上下文中需要不同的实现时。

工作流程

策略模式的工作流程可以描述为以下几个步骤:

  1. 定义策略接口(Strategy Interface):首先,定义一个策略接口,该接口包含了需要实现的算法方法。这个接口可以是一个抽象类或者一个纯虚函数接口,具体取决于编程语言和具体需求。

  2. 实现具体策略类(Concrete Strategy Classes):接下来,为每个具体的算法实现类编写具体的策略类。这些类实现了策略接口,并提供了具体的算法逻辑。

  3. 创建上下文类(Context Class):定义一个上下文类,它包含了一个指向策略接口的引用。上下文类负责在运行时根据具体的情况选择合适的策略,并将任务委托给策略对象。

  4. 设置和切换策略:在上下文类中提供设置和切换策略的方法,使得客户端可以根据需要选择不同的策略。

  5. 客户端调用:客户端创建上下文对象,并根据具体的需求选择合适的策略,并调用相应的方法执行算法。

代码实现

#include <iostream>

// 定义策略接口
class Strategy {
public:
    virtual void execute() = 0;
    virtual ~Strategy() {}
};

// 实现具体策略类
class ConcreteStrategyA : public Strategy {
public:
    void execute() override {
        std::cout << "Executing strategy A" << std::endl;
    }
};

class ConcreteStrategyB : public Strategy {
public:
    void execute() override {
        std::cout << "Executing strategy B" << std::endl;
    }
};

// 创建上下文类
class Context {
public:
    Context(Strategy* strategy) : strategy(strategy) {}

    // 设置和切换策略
    void setStrategy(Strategy* newStrategy) {
        strategy = newStrategy;
    }

    // 调用策略方法
    void executeStrategy() {
        strategy->execute();
    }

private:
    Strategy* strategy;
};

int main() {
    // 创建具体策略对象
    ConcreteStrategyA strategyA;
    ConcreteStrategyB strategyB;

    // 创建上下文对象,并设置初始策略
    Context context(&strategyA);

    // 执行初始策略
    context.executeStrategy(); // 输出 "Executing strategy A"

    // 切换策略并执行
    context.setStrategy(&strategyB);
    context.executeStrategy(); // 输出 "Executing strategy B"

    return 0;
}

在这个示例中,Strategy 是策略接口,定义了执行策略的方法。ConcreteStrategyAConcreteStrategyB 是具体策略类,分别实现了策略接口中的方法,即具体的算法实现。Context 是上下文类,它包含一个策略接口的引用,并提供了设置策略和执行策略的方法。在 main 函数中,创建了具体策略对象和上下文对象,并使用上下文对象执行了具体的策略。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1686917.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大语言模型是通用人工智能的实现路径吗?【文末有福利】

相关说明 这篇文章的大部分内容参考自我的新书《解构大语言模型&#xff1a;从线性回归到通用人工智能》&#xff0c;欢迎有兴趣的读者多多支持。 关于大语言模型的内容&#xff0c;推荐参考这个专栏。 内容大纲 相关说明一、哲学与人工智能二、内容简介三、书籍简介与福利粉…

飞睿智能超宽带UWB标签模组,简化设备开发流程,实时高速率数传交互应用

在科技飞速发展的今天&#xff0c;UWB超宽带技术因其高精度、低功耗和高安全性的特点&#xff0c;正逐渐成为智能设备定位和数据传输的新宠。 UWB技术是一种无线通信技术&#xff0c;它通过使用非常宽的频带进行数据传输&#xff0c;从而实现高数据传输速率和高精度定位。 飞…

「51媒体」线下活动媒体同步直播,云分发,分流直播

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 线下活动除了邀请嘉宾&#xff0c;邀请媒体&#xff0c;邀请行业大咖KOL&#xff0c;来为活动站台&#xff0c;背书外&#xff0c;我们也可以将线下的活动同步在线上进行直播&#xff0c…

构建 Elastic Cloud Serverless

作者&#xff1a;来自 Elastic Jason Tedor Elastic Cloud Serverless 架构 2022 年 10 月&#xff0c;我们引入了 Elasticsearch 的无状态架构。 我们该计划的主要目标是发展 Elasticsearch&#xff0c;以利用云原生服务提供的操作、性能和成本效率。 该计划成为我们最近宣…

解决Ubuntu无法使用root登录的问题

1、登录普通用户 2、使用vi编辑器打开/etc/pam.d/gdm-autologin并注释掉auth required pam_succeed_if.so user ! root quiet_success 3、使用vi编辑器打开/etc/pam.d/gdm-password并注释掉auth required pam_succeed_if.so user ! root quiet_success 4、注销用户重新用roo…

【Linux安全】Firewalld防火墙

目录 一.Firewalld概述 二.Firewalld和iptables的关系 1.firewalld和iptables的联系 2.firewalld和iptables的区别 三.Firewalld区域 1.概念 2.九个区域 3.区域介绍 4.Firewalld数据处理流程 四.Firewalld-cmd命令行操作 1.查看 2.增加 3.删除 4.修改 五.Firewa…

最新FinalShell专业版激活

支持的版本 可以激活任意版本的FinalShell为专业版&#xff0c;包括最新版4.3.10 激活方式 打开FinalShell&#xff0c;点击左下角 激活/升级。 账号密码任意输入几个字符&#xff0c;点离线激活。 复制机器码&#xff0c;将机器码发送给微信公众号【小白学算法】,即可获…

数据结构学习/复习15--排序部分复习总结

一、学过的排序 1.插入排序 2.希尔排序 3.直接选择排序 4.堆排序 5.冒泡排序 6.快速排序 7.归并排序 8.计数排序 二、各项排序的思想及改进(无特殊说明均以升序为例) 1.插入排序及其改进希尔排序 &#xff08;1&#xff09;插入排序的思想及具体操作细节 将一个数字按顺…

pytorch使用gpu训练模型

前言 仅记录学习过程&#xff0c;有问题欢迎讨论 因为网上博客参差不齐&#xff0c;我也踩了很多坑&#xff0c;留下我自己成功的经验哈哈。 1.安装CUDA和CUDNN 参考这个博客&#xff1a; https://blog.csdn.net/shdabai/article/details/131248257 2.安装gpu版本 pytorch …

【openlayers系统学习】3.6-3.7添加可视化选择器,手动选择可视化的图像源

六、添加可视化选择器&#xff08;选择可视化的图像类型&#xff09; 在前面的示例中&#xff0c;我们已经看到了同一Sentinel-2图像的真彩色合成、假彩色合成和NDVI渲染。如果能让用户从这些可视化中选择一个或更多&#xff0c;而不必每次都更改我们的代码&#xff0c;那就太…

【热门话题】一文带你读懂公司是如何知道张三在脉脉上发了“一句话”的

按理说呢&#xff0c;A公司和脉脉属于不同的平台&#xff0c;而且脉脉上大家可以匿名发言&#xff0c;所以&#xff0c;即便我坐在你边上&#xff0c;我发了一句话上去&#xff0c;你也不知道是谁发的。但通过一些技术&#xff0c;我们却可以分析出&#xff0c;公司是如何知道张…

Git远程控制

文章目录 1. 创建仓库1.1 Readme1.2 Issue1.3 Pull request 2. 远程仓库克隆3. 推送远程仓库4. 拉取远程仓库5. 配置Git.gitignore配置别名 使用GitHub可以&#xff0c;采用Gitee也行 1. 创建仓库 1.1 Readme Readme文件相当于这个仓库的说明书&#xff0c;gitee会初始化2两份…

docker容器安装nexus3以及nexus3备份迁移仓库数据

一、安装步骤 1.搜索nexus3镜像 docker search nexus3 2.拉取镜像 docker pull sonatype/nexus3或者指定版本 docker pull sonatype/nexus3:3.68.0 3.查看拉取的镜像 docker images | grep "nexus3" 4.启动nexus服务 直接启动 docker run -d --name nexus3 -…

基于Django框架深度学习口罩检测系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景与意义 随着全球疫情的蔓延&#xff0c;口罩成为了重要的防护工具。然而&#xff0c;在实际场景中&am…

MySQL —— 复合查询

一、基本的查询回顾练习 前面两章节整理了许多关于查询用到的语句和关键字&#xff0c;以及MySQL的内置函数&#xff0c;我们先用一些简单的查询练习去回顾之前的知识 1. 前提准备 同样是前面用到的用于测试的表格和数据&#xff0c;一张学生表和三张关于雇员信息表 雇员信息…

qt 布局学习笔记

目录 管理信息列表源码 c版&#xff1a; pro文件&#xff1a; qt 设置水平布局&#xff0c;里面有两个按钮&#xff0c;每个按钮就变的很宽&#xff0c;怎么设置按钮的精确位置 设置固定大小&#xff1a; 使用弹性空间&#xff08;Spacer&#xff09; 使用布局比例&…

Apache Doris 基础(一) -- Getting Started

Apache Doris 开源、实时数据仓库 Apache Doris是一个用于实时分析的现代数据仓库。 它提供大规模闪电般的实时数据分析。 实时获取和存储 在一秒钟内基于推的微批处理和基于拉的流数据获取。实时更新&#xff0c;追加和预聚合的存储引擎闪电般的查询 使用列式存储引擎、MPP架构…

vue3封装ElementUI plus Dialog弹窗

因为ElementuiPlus的dialog弹框的初始样式不太好看,而公司要求又要好看,本来是已经实现了,但是后来想想了发现封装完dialog的其他功能也要,所以特此记录一下 方案一 思路:封装一个组件,将所有新增的参数引入el-dialog 参数中,实现参数共用 新建一个组件,将官网暴露的属性全部引…

达梦数据库详解

达梦认证是指针对中国数据库管理系统&#xff08;DBMS&#xff09;厂商达梦公司所推出的数据库产品&#xff0c;即达梦数据库&#xff08;DMDB&#xff09;&#xff0c;进行的一种官方认证体系。达梦认证旨在验证数据库管理人员对达梦数据库产品的掌握程度&#xff0c;及其在数…

【AD936X】 SDR 版图 欣赏

DIE : 4336x4730 um 的 65 nm 芯片 在顶部金属上&#xff0c;您可以看到 PLL 的电感器和日期代码 - 芯片在推出前两年就已准备就绪&#xff1a; 右下角是主数字块&#xff0c;应该是 128 抽头 FIR 滤波器。在最大放大倍率下&#xff0c;我们可以看到一排排标准单元。它们的放置…