六种常用设计模式

单例设计模式

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

单例模式分类

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

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

单例类特点

  • 构造函数和析构函数为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,并包装具体装饰器ADecorator* 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.mzph.cn/web/14099.shtml

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

相关文章

SpringBootWeb 篇-深入了解 Mybatis 删除、新增、更新、查询的基础操作与 SQL 预编译解决 SQL 注入问题

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 Mybatis 的基础操作 2.0 基础操作 - 环境准备 3.0 基础操作 - 删除操作 3.1 SQL 预编译 3.2 SQL 预编译的优势 3.3 参数占位符 4.0 基础操作 - 新增 4.1 主键返回…

Python图像处理:从基础到高级的全方位指南

目录 第一部分&#xff1a;Python图像处理基础 1.1 图像处理概念 1.2 Python图像处理常用库 1.3 实战案例&#xff1a;图像显示与保存 1.4 注意事项 第二部分&#xff1a;Python图像处理高级技巧 2.1 图像变换 2.2 图像增强 2.3 图像复原 第三部分&#xff1a;Python…

20232802 黄千里 2023-2024-2 《网络攻防实践》实践十一报告

20232802 2023-2024-2 《网络攻防实践》实践十一报告 1.实践过程 1.1web浏览器渗透攻击 攻击机&#xff1a;kali172.20.10.10靶机&#xff1a;win2k172.20.10.3 首先在kali中启动msfconsole 输入命令search MS06-014&#xff0c;搜索渗透攻击模块 输入use exploit/window…

终于让我找到了,你也可以学会的人工智能-机器学习教程

给大家分享一套非常棒的python机器学习课程——《AI小天才&#xff1a;让小学生轻松掌握机器学习》&#xff0c;2024年5月完结新课&#xff0c;提供配套的代码笔记软件包下载&#xff01;学完本课程&#xff0c;可以轻松掌握机器学习的全面应用&#xff0c;复杂特征工程&#x…

关于新配置的adb,设备管理器找不到此设备问题

上面页面中一开始没有找到此android设备&#xff0c; 可能是因为我重新配置的adb和设备驱动&#xff0c; 只把adb配置了环境变量&#xff0c;驱动没有更新到电脑中&#xff0c; 点击添加驱动&#xff0c; 选择路径&#xff0c;我安装时都放在了SDK下面&#xff0c;可以尝试…

SpringBoot 实现 RAS+AES 自动接口解密

一、讲个事故 接口安全老生常谈了 过年之前做了过一款飞机大战的H5小游戏&#xff0c;里面无限模式-需要保存用户的积分&#xff0c;因为使用的Body传参&#xff0c;参数是可见的。 为了接口安全我&#xff0c;我和前端约定了传递参数是&#xff1a;用户无限模式的积分“我们…

HTML静态网页成品作业(HTML+CSS)——魅族商城首页网页(1个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有1个页面。 二、作品演示 三、代…

基于Python+OpenCV卷积神经网络的字符识别

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景与意义 字符识别是计算机视觉和模式识别领域的一个重要应用&#xff0c;它在文档数字化、车牌识别、验…

gpt-4o考场安排

说明 &#xff1a;经过多次交互&#xff0c;前后花了几个小时&#xff0c;总算完成了基本功能。如果做到按不同层次分配考场&#xff0c;一键出打印结果就完美了。如果不想看中间“艰苦”的过程&#xff0c;请直接跳到“最后结果”及“食用方法”。中间过程还省略了一部分交互&…

go slice 扩容

扩容 slice 会迁移到新的内存位置&#xff0c;新底层数组的长度也会增加&#xff0c;这样就可以放置新增的元素。同时&#xff0c;为了应对未来可能再次发生的 append 操作&#xff0c;新的底层数组的长度&#xff0c;也就是新 slice 的容量是留了一定的 buffer 的。否则&…

【C++】STL快速入门基础

文章目录 STL&#xff08;Standard Template Library&#xff09;1、一般介绍2、STL的六大组件2.1、STL容器2.2、STL迭代器2.3、相关容器的函数vectorpairstringqueuepriority_queuestackdequeset, map, multiset, multimapunordered_set, unordered_map, unordered_multiset, …

LabVIEW2022安装教程指南【附安装包】

文章目录 前言一、安装指南1、软件包获取 二、安装步骤总结 前言 LabVIEW是一种程序开发环境&#xff0c;提供一种图形化编程方法&#xff0c;可可视化应用程序的各个方面&#xff0c;包括硬件配置、测量数据和调试&#xff0c;同时可以通过FPGA数学和分析选板中的NI浮点库链接…

有趣的css - 两个圆形加载效果

大家好&#xff0c;我是 Just&#xff0c;这里是「设计师工作日常」&#xff0c;今天分享的是一款小清新的加载动画&#xff0c;适用于 app 列表加载&#xff0c;页面加载或者弹层内容延迟加载等场景。 最新文章通过公众号「设计师工作日常」发布。 目录 整体效果核心代码html…

20年交易老兵悟出的宝贵经验,做到这10点或许你也能躺着赚钱

交易要靠亲身体验来真正获得发展&#xff0c;在正确引导下&#xff0c;我们就不会把时间和精力浪费在弯路上。交易之技易学&#xff0c;实难在心态与思考。接下来&#xff0c;我将与您分享一位交易了20年的老兵所积累的10条珍贵经验。 Nial Fuller,一个交易了接近20年的市场“老…

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两份…

go mod模式下,import gitlab中的项目

背景 为了go项目能够尽可能复用代码&#xff0c;把一些公用的工具类&#xff0c;公用的方法等放到共用包里统一管理。把共用包放到gitlab的私有仓库中。 遇到的问题 通过https方式&#xff0c;执行go get报了错误。 通过ssh方式&#xff0c;执行go get报了错误。 修改配置&am…

面试八股之MySQL篇2——索引篇

&#x1f308;hello&#xff0c;你好鸭&#xff0c;我是Ethan&#xff0c;一名不断学习的码农&#xff0c;很高兴你能来阅读。 ✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。 &#x1f3c3;人生之义&#xff0c;在于追求&#xff0c;不在成败&#xff0c;勤通…

Springboot阶段项目---《书城项目》

一 项目介绍 本项目采用集成开发平台IntelliJ IDEA开发了在线作业成绩统计系统的设计与实现&#xff0c;实现了图书商城系统的综合功能和图形界面的显示&#xff0c;可以根据每个用户登录系统后&#xff0c;动态展示书城首页图书&#xff0c;实现了分类还有分页查询&#xff0c…

Linux应用入门(二)

1. 输入系统应用编程 1.1 输入系统介绍 常见的输入设备有键盘、鼠标、遥控杆、书写板、触摸屏等。用户经过这些输入设备与Linux系统进行数据交换。这些设备种类繁多&#xff0c;如何去统一它们的接口&#xff0c;Linux为了统一管理这些输入设备实现了一套能兼容所有输入设备的…

怎么压缩pdf pdf在线压缩 pdf文件压缩大小

pdf文件无论在何种设备上打开&#xff0c;PDF文件都能保持其原始的布局和格式&#xff0c;这对于文档共享和打印非常重要。PDF不仅支持文本&#xff0c;还能嵌入图像、视频、音频以及动态链接等元素。PDF文件支持加密和密码保护&#xff0c;可以限制访问、编辑、复制或打印文档…