六种常用设计模式

单例设计模式

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

单例模式分类

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

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

单例类特点

  • 构造函数和析构函数为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 函数中,创建了具体策略对象和上下文对象,并使用上下文对象执行了具体的策略。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于Python实现 HR 分析(逻辑回归和基于树的机器学习)【500010104】

介绍 数据集说明 此数据集包含与员工有关的综合属性集合&#xff0c;从人口统计细节到与工作相关的因素。该分析的主要目的是预测员工流动率并辨别导致员工流失的潜在因素。 在这个数据集中&#xff0c;有14,999行&#xff0c;10列&#xff0c;以及这些变量&#xff1a;满意度…

【Python】 如何使用逗号作为千位分隔符打印数字

基本原理 在Python中&#xff0c;打印数字时自动添加千位分隔符可以提高数字的可读性&#xff0c;尤其是在处理大数字时。Python提供了多种方法来实现这一功能&#xff0c;包括使用内置的format()函数、f-string&#xff08;格式化字符串字面量&#xff09;以及locale模块。 …

数据量较小的表是否有必要添加索引问题分析

目录 前言一、分析前准备1.1、准备测试表和数据1.2、插入测试数据1.3、测试环境说明 二、具体业务分析2.1、单次查询耗时分析2.2、无索引并发查询服务器CPU占用率分析2.3、添加索引并发查询服务器CPU占用率分析 三、总结 前言 在一次节日活动我们系统访问量到达了平时的两倍&am…

50道题目!Python、SQL数据库、AB测试、业务分析、机器学习都在这里了!

介绍 每日一题系列已经更新了50道题目啦&#xff01; 题目难度为初级到中级&#xff0c;涵盖了Python、SQL数据库、AB测试、业务分析、机器学习五大主题&#xff0c;适合初学者和有一定基础的朋友。 原文链接: 50道题目&#xff01;Python、SQL数据库、AB测试、业务分析、机器…

达梦数据库详解

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

LoRA:大型语言模型的低秩适应

LoRA 官网 LoRA(Low-Rank Adaptation)出自2021年的论文“LoRA: Low-Rank Adaptation of Large Language Models” 常见的大模型微调方法&#xff1a; Adapter-Tuning、Prefix-Tuning、Prompt-Tuning(P-Tuning)、P-Tuning v2、LoRA。 LoRA技术冻结预训练…

冬奥会|基于SprinBoot+vue的冬奥会科普平台(源码+数据库+文档)

目录 基于SprinBootvue的冬奥会科普平台 一、前言 二、系统设计 三、系统功能设计 1登录注册 2系统功能模块 3管理员功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|…

Discourse 使用 DiscourseConnect 调用接口 admin/users/sync_sso 404 错误

在对用户数据通过 SSO 同步的时候&#xff0c;调用提示 404 错误。 我们使用的是 Java 的代码。 2024-05-23_16-34-421340802 70.3 KB 如上图&#xff0c;返回显示的代码为 404。 问题原因 出现上面错误的原因是安装的 Discourse 实例的 discourse connect 没有启用。 2024-…

【C语言】明析部分C语言内存函数

目录 1.memcpy 2.memmove 3.memset 4.memcmp 以下都是内存函数&#xff0c;作用单位均是字节 1.memcpy memcpy是C/C语言中的一个内存拷贝函数&#xff0c;其原型为&#xff1a; void* memcpy(void* dest, const void* src, size_t n);目标空间&#xff08;字节&#xff09…

作家百度百科怎么做出来的 怎么创建作家百科词条才能通过

创建作家百度百科词条需要遵循一定的步骤&#xff0c;并注意一些关键点&#xff0c;以确保词条能够顺利通过审核。以下是伯乐网络传媒pouquan根据经验结果得出的详细指导&#xff1a; 准备工作 注册百度账号&#xff1a;在创建任何百度百科词条之前&#xff0c;您需要先注册一…

Milvus的内存索引

简介&#xff1a; 这篇文章主要介绍milvus支持的各种内存索引&#xff0c;以及它们最适用的场景&#xff0c;还有用户为了获得更好的搜索性能可以配置的参数。 索引是有效组织数据的过程&#xff0c;它的主要角色是在大的数据集中显著的加速耗时的查询从而有效的进行相似搜索…

常见的100个Shell命令,超级实用!

在大多数的Linux和Unix系统、及其他类Unix系统中&#xff0c;Shell是用户与操作系统内核交互的主要方式。作为一种强大的命令行解释器&#xff0c;它也支持编程功能&#xff0c;用户可以写脚本来处理各种任务。 熟悉shell脚本&#xff0c;首先要对shell指令熟悉&#xff0c;今…

Python图形界面(GUI)Tkinter笔记(八):用【Label()】方法制作九九乘数表

主要是使用"config()"方法来体现函数式、模块化的美好风景。把需随时要修改的控件参数定义在“config()”方法里且把它封装在一个函数中&#xff0c;这时只需对这函数内的“config()”方法作出相应的修改即可&#xff0c;无需对主代码或全部代码重新修一遍。这也是Py…

【Spring】spring入门程序

案例要求&#xff1a;创建一个 Studentservice 类&#xff0c;其中需要使用 studentDao 接口的保存方法&#xff0c;来存储一个Student 类的对象&#xff0c;StudentDao 接口有两个不同的实现类&#xff0c;通过 Spring 的方式&#xff0c;为 Student类创建对象并为属性赋值&am…

react【框架原理详解】JSX 的本质、SyntheticEvent 合成事件机制、组件渲染过程、组件更新过程

JSX 的本质 JSX 代码本身并不是 HTML&#xff0c;也不是 Javascript&#xff0c;在渲染页面前&#xff0c;需先通过解析工具&#xff08;如babel&#xff09;解析之后才能在浏览器中运行。 babel官网可查看 JSX 解析后的效果 更早之前&#xff0c;Babel 会把 JSX 转译成一个 R…

论文精读:UFO: A UI-Focused Agent for Windows OS Interaction

UFO : A UI-Focused Agent for Windows OS Interaction Status: Reading Author: Bo Qiao, Chaoyun Zhang, Dongmei Zhang, Liqun Li, Minghua Ma, Qinglong Zhang, Qingwei Lin, Saravan Rajmohan, Shilin He, Si Qin, Xiangyu Zhang, Yu Kang Institution: 微软&#xff08;…

骑行之旅,骑行之旅,骑行之旅

骑行之旅其一&#xff1a;晨曦破晓普吉路&#xff0c;铁骑奔腾向远方。小桃园中寻雅趣&#xff0c;保利春湖泛波光。落水洞边环水库&#xff0c;田冲村里话家常。秧草塘畔风情美&#xff0c;白泥塘中歌声扬。陡普鲁村享盛宴&#xff0c;AA 制下笑语长。赛道体验激情涌&#xff…

有什么免费的文字转语音软件?这5个文字转语音工具超简单

听说你对最近备受瞩目的文字转语音技术很感兴趣&#xff1f; 文字转语音技术&#xff0c;就是一种将文本转换为自然语音的技术&#xff0c;它让机器发音听起来就像真人一样。那么&#xff0c;市面上的文字转语音软件种类繁多&#xff0c;选择起来就有些困难了。 别担心&#…

【cocos creator】进度条控制脚本,支持节点进度条,图片进度条,进度条组件,和进度文字展示

进度条控制脚本&#xff0c;支持节点进度条&#xff0c;图片进度条&#xff0c;进度条组件&#xff0c;和进度文字展示 const { ccclass, property, menu } cc._decorator;let text_type cc.Enum({"20%": 0,"1/5": 1,"差值": 2,"自定义…

开放式耳机怎么选择!教你几招!2024开放式蓝牙耳机推荐

在面对市场上琳琅满目的开放式耳机时&#xff0c;许多用户可能会感到难以抉择。作为一名开放式耳机的爱好者&#xff0c;我根据自己的实际使用体验&#xff0c;整理了一些我认为值得推荐的开放式耳机&#xff0c;希望能为正在寻找合适耳机的朋友们提供一些参考和帮助。我将为大…