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

C++设计模式

C++设计模式

  • 什么是 C++ 设计模式?
    • 设计模式的用途
    • 设计模式的核心原则
    • 设计模式的分类
  • 1. 创建型设计模式
    • 1.1 单例模式(Singleton Pattern)
    • 1.2 工厂方法模式(Factory Method Pattern)
    • 1.3 抽象工厂模式(Abstract Factory Pattern)
    • 1.4 建造者模式(Builder Pattern)
    • 1.5 原型模式(Prototype Pattern)
  • 2. 结构型设计模式
    • 2.1 适配器模式(Adapter Pattern)
    • 2.2 装饰器模式(Decorator Pattern)
    • 2.3 代理模式(Proxy Pattern)
    • 2.4 外观模式(Facade Pattern)
    • 2.5 组合模式(Composite Pattern)
    • 2.6 桥接模式(Bridge Pattern)
  • 3. 行为型设计模式
    • 3.1 策略模式(Strategy Pattern)
    • 3.2 观察者模式(Observer Pattern)
    • 3.3 状态模式(State Pattern)
    • 3.4 命令模式(Command Pattern)
    • 3.5 责任链模式(Chain of Responsibility Pattern)

什么是 C++ 设计模式?

设计模式(Design Patterns) 是对在软件开发过程中反复出现的常见问题的解决方案的总结和概括。它们提供了一种可复用的、通用的设计方法,帮助开发人员解决软件设计中常见的结构性和行为性问题。设计模式并不是具体的代码,而是解决特定问题的一种架构思路或者方案。

C++ 设计模式是指在 C++ 编程中应用的设计模式,涉及如何通过类和对象组织、解耦以及优化代码结构。设计模式帮助开发者有效地管理复杂性、提高代码的可维护性、可复用性和灵活性。

设计模式的用途

设计模式在软件开发中具有以下重要用途:

  • 提高代码复用性: 设计模式通过定义一套标准的解决方案,使得开发者能够将某些常见的设计问题抽象出来,形成通用的设计模板。这样可以减少重复劳动,提高代码的复用性。例如,工厂模式(Factory Pattern)可以帮助我们简化对象创建的过程,避免了每次都要写重复的构造代码。

  • 提高代码的可维护性: 设计模式帮助开发者构建清晰且易于理解的代码结构。它们通常遵循特定的原则和约定(如单一职责原则、开闭原则等),有助于减少代码中的耦合度和复杂性,从而提高代码的可维护性。例如,策略模式(Strategy Pattern)可以让程序在运行时动态改变算法,避免了对原有代码的修改。

  • 解耦和模块化: 设计模式帮助将系统的各个部分解耦,使得不同的模块可以独立修改和扩展。比如,观察者模式(Observer Pattern)允许对象之间松散耦合,一个对象的状态改变时,可以自动通知所有依赖的对象,而不需要直接引用它们。

  • 提高灵活性和扩展性: 设计模式帮助设计更具灵活性和可扩展性的系统。很多设计模式通过面向接口编程和继承、多态等特性来提供扩展点。例如,桥接模式(Bridge Pattern)通过分离抽象和实现,使得二者可以独立扩展。

  • 简化复杂系统的设计: 设计模式通过标准化的方式组织系统,使得开发人员能够更容易理解系统的结构,降低理解和使用的难度。例如,外观模式(Facade Pattern)可以将一个复杂子系统封装成简单的接口,简化客户端的操作。

  • 增强代码的可测试性: 设计模式通常提倡将复杂逻辑分离成独立的模块或类,使得各个模块的功能单一且清晰。这使得代码更容易进行单元测试。例如,命令模式(Command Pattern)可以将请求封装为对象,从而方便进行单元测试和请求的记录。

  • 适应变化: 设计模式帮助程序应对未来的变化,提供灵活的解决方案。在软件开发中,需求变化是不可避免的,设计模式为系统的扩展和修改提供了良好的基础。例如,状态模式(State Pattern)可以根据状态变化动态改变对象的行为,避免了使用大量条件语句的困扰。

设计模式的核心原则

设计模式通常基于一些面向对象设计的基本原则,如:

  • 单一职责原则(Single Responsibility Principle, SRP): 每个类应该只有一个职责,并且该职责应该由类中的所有方法协同完成。

  • 开闭原则(Open/Closed Principle, OCP): 软件实体应该对扩展开放,对修改关闭。也就是说,通过增加新的代码来扩展系统的功能,而不需要修改现有的代码。

  • 里氏替换原则(Liskov Substitution Principle, LSP): 子类应该可以替换父类,且程序的功能不受影响。

  • 依赖倒转原则(Dependency Inversion Principle, DIP): 高层模块不应该依赖低层模块,二者应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象。

  • 接口隔离原则(Interface Segregation Principle, ISP): 一个类不应该强迫其实现的接口方法对它不感兴趣的代码进行依赖。

设计模式的分类

设计模式通常分为以下三大类:

  • 创建型模式(Creational Patterns):与对象的创建过程相关,主要解决如何实例化对象的问题,确保对象的创建过程适应变化。
    例如:工厂模式(Factory Pattern)、抽象工厂模式(Abstract Factory Pattern)、单例模式(Singleton Pattern)等。

  • 结构型模式(Structural Patterns):与类和对象的组合结构相关,主要解决如何组合和组织类、对象的问题。
    例如:适配器模式(Adapter Pattern)、外观模式(Facade Pattern)、桥接模式(Bridge Pattern)等。

  • 行为型模式(Behavioral Patterns):与对象之间的通信和责任分配相关,主要解决如何分配和协调对象之间的责任和交互的问题。
    例如:观察者模式(Observer Pattern)、策略模式(Strategy Pattern)、命令模式(Command Pattern)等。

1. 创建型设计模式

创建型设计模式关注如何实例化对象,尤其是在复杂的对象创建过程中。其主要目标是将对象的创建与使用解耦,使系统能够灵活地管理对象的创建过程。

1.1 单例模式(Singleton Pattern)

单例模式确保一个类只有一个实例,并提供一个全局访问点。这种模式通常用于需要集中控制资源的场景,如配置管理、日志管理、线程池等。

  • 优点:
    控制实例数量,确保全局共享。
    延迟初始化,节省资源。
  • 缺点:
    隐藏了类的依赖关系,可能导致系统的耦合性增加。
    在多线程环境下需要特别注意线程安全问题。
class Singleton {
private:static Singleton* instance;// 私有构造函数,防止外部实例化Singleton() {}public:static Singleton* getInstance() {if (!instance) {instance = new Singleton();}return instance;}void showMessage() {std::cout << "Hello, Singleton!" << std::endl;}
};// 初始化静态实例
Singleton* Singleton::instance = nullptr;int main() {Singleton* s1 = Singleton::getInstance();s1->showMessage(); // 输出:Hello, Singleton!return 0;
}

1.2 工厂方法模式(Factory Method Pattern)

工厂方法模式通过定义一个创建对象的接口,让子类决定实例化哪个类。这样,创建对象的代码被封装在工厂方法内部,客户端不需要直接依赖具体的类。

  • 优点:
    客户端代码不依赖具体类,而是依赖抽象工厂。
    更容易扩展新的产品类。
  • 缺点:
    增加了类的数量,可能导致系统变得复杂。
class Product {
public:virtual void doSomething() = 0;virtual ~Product() = default;
};class ConcreteProductA : public Product {
public:void doSomething() override {std::cout << "Product A doing something!" << std::endl;}
};class ConcreteProductB : public Product {
public:void doSomething() override {std::cout << "Product B doing something!" << std::endl;}
};class Creator {
public:virtual Product* factoryMethod() = 0;virtual ~Creator() = default;
};class ConcreteCreatorA : public Creator {
public:Product* factoryMethod() override {return new ConcreteProductA();}
};class ConcreteCreatorB : public Creator {
public:Product* factoryMethod() override {return new ConcreteProductB();}
};int main() {Creator* creatorA = new ConcreteCreatorA();Product* productA = creatorA->factoryMethod();productA->doSomething(); // 输出:Product A doing something!Creator* creatorB = new ConcreteCreatorB();Product* productB = creatorB->factoryMethod();productB->doSomething(); // 输出:Product B doing something!delete productA;delete productB;delete creatorA;delete creatorB;return 0;
}

1.3 抽象工厂模式(Abstract Factory Pattern)

抽象工厂模式提供一个接口,用于创建一系列相关或依赖的对象,而无需指定具体的类。常用于产品族的创建,例如,在跨平台应用中根据不同操作系统创建不同的GUI组件。

  • 优点:
    使得客户端能够在不同的产品族之间进行选择。
    避免了依赖具体类的情况。
  • 缺点:
    增加了系统的复杂性,可能需要管理更多的接口和实现类。
class Button {
public:virtual void render() = 0;virtual ~Button() = default;
};class WinButton : public Button {
public:void render() override {std::cout << "Rendering Windows Button" << std::endl;}
};class MacButton : public Button {
public:void render() override {std::cout << "Rendering Mac Button" << std::endl;}
};class GUIFactory {
public:virtual Button* createButton() = 0;virtual ~GUIFactory() = default;
};class WinFactory : public GUIFactory {
public:Button* createButton() override {return new WinButton();}
};class MacFactory : public GUIFactory {
public:Button* createButton() override {return new MacButton();}
};int main() {GUIFactory* factory = new WinFactory();Button* button = factory->createButton();button->render(); // 输出:Rendering Windows Buttondelete button;delete factory;return 0;
}

1.4 建造者模式(Builder Pattern)

建造者模式通过使用多个步骤构建复杂的对象,将对象的构建过程与它的表示分离。这种模式适用于构建具有复杂结构的对象。

  • 优点:
    分离了对象的构建过程和表示,便于代码的组织。
    使得代码更加灵活,易于扩展。
  • 缺点:
    需要较多的代码来处理对象的创建。
class Product {
public:void addPart(const std::string& part) {parts.push_back(part);}void show() {for (const auto& part : parts) {std::cout << part << std::endl;}}private:std::vector<std::string> parts;
};class Builder {
public:virtual void buildPart1() = 0;virtual void buildPart2() = 0;virtual Product* getResult() = 0;virtual ~Builder() = default;
};class ConcreteBuilder : public Builder {
private:Product* product = new Product();public:void buildPart1() override {product->addPart("Part 1");}void buildPart2() override {product->addPart("Part 2");}Product* getResult() override {return product;}~ConcreteBuilder() {delete product;}
};int main() {Builder* builder = new ConcreteBuilder();builder->buildPart1();builder->buildPart2();Product* product = builder->getResult();product->show();  // 输出:Part 1  Part 2delete builder;delete product;return 0;
}

1.5 原型模式(Prototype Pattern)

原型模式通过复制现有对象来创建新对象。适用于创建大量相似对象的场景,如需要克隆的复杂对象。

  • 优点:
    通过复制现有实例来创建新对象,避免了重复创建的开销。
    可以动态地决定哪些对象可以被克隆。
  • 缺点:
    对象的克隆过程可能会变得复杂,特别是当对象的内部结构较为复杂时。
class Prototype {
public:virtual Prototype* clone() = 0;virtual void show() = 0;virtual ~Prototype() = default;
};class ConcretePrototype : public Prototype {
private:std::string data;public:ConcretePrototype(const std::string& d) : data(d) {}Prototype* clone() override {return new ConcretePrototype(*this);}void show() override {std::cout << "Data: " << data << std::endl;}
};int main() {ConcretePrototype* original = new ConcretePrototype("Original");original->show();  // 输出:Data: OriginalConcretePrototype* clone = static_cast<ConcretePrototype*>(original->clone());clone->show();  // 输出:Data: Originaldelete original;delete clone;return 0;
}

2. 结构型设计模式

结构型设计模式关注如何将类和对象组合成更大的结构,目的是提高系统的可扩展性和灵活性。

2.1 适配器模式(Adapter Pattern)

适配器模式通过将一个类的接口转换为客户端所期望的接口,解决了接口不兼容的问题。通常用于使不兼容的类可以一起工作。

  • 优点:
    可以让不兼容的类协同工作,避免修改原有代码。
    提供更高的灵活性,能够复用现有的类。
  • 缺点:
    可能会增加系统的复杂性,尤其是在大量适配器的情况下。
class Target {
public:virtual void request() = 0;
};class Adaptee {
public:void specificRequest() {std::cout << "Specific request" << std::endl;}
};class Adapter : public Target {
private:Adaptee* adaptee;public:Adapter(Adaptee* a) : adaptee(a) {}void request() override {adaptee->specificRequest();}
};int main() {Adaptee* adaptee = new Adaptee();Target* target = new Adapter(adaptee);target->request();  // 输出:Specific requestdelete adaptee;delete target;return 0;
}

2.2 装饰器模式(Decorator Pattern)

装饰器模式允许动态地为一个对象添加额外的职责。装饰器模式提供了一种灵活的方式来扩展类的功能,而不需要修改类本身。

  • 优点:
    可以在运行时动态地改变对象的行为。
    避免使用继承来扩展功能,减少了类的数量。
  • 缺点:
    增加了系统的复杂度,尤其是装饰器层次较深时。
class Component {
public:virtual void operation() = 0;virtual ~Component() = default;
};class ConcreteComponent : public Component {
public:void operation() override {std::cout << "ConcreteComponent operation" << std::endl;}
};class Decorator : public Component {
protected:Component* component;public:Decorator(Component* c) : component(c) {}void operation() override {component->operation();}
};class ConcreteDecoratorA : public Decorator {
public:ConcreteDecoratorA(Component* c) : Decorator(c) {}void operation() override {Decorator::operation();std::cout << "ConcreteDecoratorA additional behavior" << std::endl;}
};int main() {Component* simple = new ConcreteComponent();Component* decorated = new ConcreteDecoratorA(simple);decorated->operation();// 输出:// ConcreteComponent operation// ConcreteDecoratorA additional behaviordelete simple;delete decorated;return 0;
}

2.3 代理模式(Proxy Pattern)

代理模式通过提供一个代理对象来控制对目标对象的访问。常见的代理类型有虚拟代理、远程代理、保护代理等。

  • 优点:
    可以延迟对象的创建和操作,节省资源。
    代理可以为目标对象添加额外的功能,如权限控制、缓存等。
  • 缺点:
    增加了系统的复杂度,尤其是涉及多个代理对象时。
class Subject {
public:virtual void request() = 0;virtual ~Subject() = default;
};class RealSubject : public Subject {
public:void request() override {std::cout << "RealSubject request" << std::endl;}
};class Proxy : public Subject {
private:RealSubject* realSubject;public:Proxy() : realSubject(nullptr) {}void request() override {if (!realSubject) {realSubject = new RealSubject();}realSubject->request();}~Proxy() {delete realSubject;}
};int main() {Proxy proxy;proxy.request();  // 输出:RealSubject requestreturn 0;
}

2.4 外观模式(Facade Pattern)

外观模式提供一个统一的接口,简化子系统的复杂度。通过外观类,客户端可以不直接接触复杂的子系统,而是通过简单的接口进行操作。

  • 优点:
    提供简单的接口,简化了子系统的使用。
    减少了系统之间的依赖,提高了系统的灵活性。
  • 缺点:
    如果外观类过于庞大,可能导致系统复杂度增加。
class SubsystemA {
public:void operationA() {std::cout << "Subsystem A operation" << std::endl;}
};class SubsystemB {
public:void operationB() {std::cout << "Subsystem B operation" << std::endl;}
};class SubsystemC {
public:void operationC() {std::cout << "Subsystem C operation" << std::endl;}
};class Facade {
private:SubsystemA* subsystemA;SubsystemB* subsystemB;SubsystemC* subsystemC;public:Facade() {subsystemA = new SubsystemA();subsystemB = new SubsystemB();subsystemC = new SubsystemC();}void doSomething() {subsystemA->operationA();subsystemB->operationB();subsystemC->operationC();}~Facade() {delete subsystemA;delete subsystemB;delete subsystemC;}
};int main() {Facade* facade = new Facade();facade->doSomething();delete facade;return 0;
}

输出

Subsystem A operation
Subsystem B operation
Subsystem C operation

2.5 组合模式(Composite Pattern)

组合模式将对象组合成树形结构,客户可以像处理单个对象一样处理这些对象的集合。通常用于表示树形结构的数据。

  • 优点:
    客户端可以统一处理单个对象和对象组合。
    方便增加新的组件或叶子节点类型。
  • 缺点:
    组合模式的使用可能会导致过度泛化,增加设计的复杂性。
class Component {
public:virtual void operation() = 0;virtual ~Component() = default;
};class Leaf : public Component {
public:void operation() override {std::cout << "Leaf operation" << std::endl;}
};class Composite : public Component {
private:std::vector<Component*> children;public:void add(Component* component) {children.push_back(component);}void operation() override {std::cout << "Composite operation" << std::endl;for (auto* child : children) {child->operation();}}~Composite() {for (auto* child : children) {delete child;}}
};int main() {Leaf* leaf1 = new Leaf();Leaf* leaf2 = new Leaf();Composite* composite = new Composite();composite->add(leaf1);composite->add(leaf2);composite->operation();delete composite;return 0;
}

输出

Composite operation
Leaf operation
Leaf operation

2.6 桥接模式(Bridge Pattern)

桥接模式通过将抽象部分与实现部分分离,使得两者可以独立地变化。通常用于需要在多个平台或环境下运行的系统。

  • 优点:
    通过桥接来解耦抽象部分和实现部分,提高灵活性。
    可以独立地扩展抽象和实现层次。
  • 缺点:
    增加了系统的复杂性,尤其是在抽象和实现层次较多时。
class Implementor {
public:virtual void operationImpl() = 0;virtual ~Implementor() = default;
};class ConcreteImplementorA : public Implementor {
public:void operationImpl() override {std::cout << "ConcreteImplementorA operation" << std::endl;}
};class ConcreteImplementorB : public Implementor {
public:void operationImpl() override {std::cout << "ConcreteImplementorB operation" << std::endl;}
};class Abstraction {
protected:Implementor* implementor;public:Abstraction(Implementor* imp) : implementor(imp) {}virtual void operation() {implementor->operationImpl();}virtual ~Abstraction() = default;
};class RefinedAbstraction : public Abstraction {
public:RefinedAbstraction(Implementor* imp) : Abstraction(imp) {}void operation() override {std::cout << "RefinedAbstraction calling: ";Abstraction::operation();}
};int main() {Implementor* impA = new ConcreteImplementorA();Abstraction* abstractionA = new RefinedAbstraction(impA);abstractionA->operation();  // 输出:RefinedAbstraction calling: ConcreteImplementorA operationImplementor* impB = new ConcreteImplementorB();Abstraction* abstractionB = new RefinedAbstraction(impB);abstractionB->operation();  // 输出:RefinedAbstraction calling: ConcreteImplementorB operationdelete impA;delete impB;delete abstractionA;delete abstractionB;return 0;
}

3. 行为型设计模式

行为型设计模式关注对象之间的交互和责任的分配,旨在提高系统的灵活性和可扩展性。

3.1 策略模式(Strategy Pattern)

策略模式定义了一系列算法,将每个算法封装起来,并使它们可以互换。策略模式让算法的变化独立于使用算法的客户端。

  • 优点:
    客户端可以在运行时选择不同的策略。
    增加新的策略时无需修改客户端代码。
  • 缺点:
    需要管理多个策略类。
class Strategy {
public:virtual void execute() = 0;virtual ~Strategy() = default;
};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 {
private:Strategy* strategy;public:Context(Strategy* s) : strategy(s) {}void setStrategy(Strategy* s) {strategy = s;}void executeStrategy() {strategy->execute();}
};int main() {ConcreteStrategyA strategyA;ConcreteStrategyB strategyB;Context context(&strategyA);context.executeStrategy();  // 输出:Executing Strategy Acontext.setStrategy(&strategyB);context.executeStrategy();  // 输出:Executing Strategy Breturn 0;
}

3.2 观察者模式(Observer Pattern)

观察者模式定义了一对多的依赖关系,当一个对象的状态变化时,所有依赖于它的对象都会收到通知并自动更新。常用于事件处理系统、消息通知等场景。

  • 优点:
    解耦了主题与观察者,便于扩展。
    支持广播通信,多个观察者可以同时接收通知。
  • 缺点:
    可能导致系统中观察者与被观察者之间的依赖关系复杂化。
class Observer {
public:virtual void update() = 0;virtual ~Observer() = default;
};class Subject {
private:std::vector<Observer*> observers;public:void addObserver(Observer* observer) {observers.push_back(observer);}void removeObserver(Observer* observer) {observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());}void notify() {for (auto* observer : observers) {observer->update();}}
};class ConcreteObserver : public Observer {
private:std::string name;public:ConcreteObserver(const std::string& n) : name(n) {}void update() override {std::cout << "Observer " << name << " is notified!" << std::endl;}
};int main() {Subject subject;ConcreteObserver* observer1 = new ConcreteObserver("Observer1");ConcreteObserver* observer2 = new ConcreteObserver("Observer2");subject.addObserver(observer1);subject.addObserver(observer2);subject.notify();  // 输出:Observer Observer1 is notified!  Observer Observer2 is notified!delete observer1;delete observer2;return 0;
}

3.3 状态模式(State Pattern)

状态模式允许对象在其内部状态改变时改变它的行为,通常用于对象的行为受其状态控制的场景。

  • 优点:
    将状态的转换逻辑与对象的其他行为解耦。
    易于管理和扩展新的状态。
  • 缺点:
    增加了类的数量,可能导致状态管理变得复杂。
class State {
public:virtual void handle() = 0;virtual ~State() = default;
};class ConcreteStateA : public State {
public:void handle() override {std::cout << "Handling in State A" << std::endl;}
};class ConcreteStateB : public State {
public:void handle() override {std::cout << "Handling in State B" << std::endl;}
};class Context {
private:State* state;public:Context(State* s) : state(s) {}void setState(State* s) {state = s;}void request() {state->handle();}
};int main() {State* stateA = new ConcreteStateA();State* stateB = new ConcreteStateB();Context* context = new Context(stateA);context->request();  // 输出:Handling in State Acontext->setState(stateB);context->request();  // 输出:Handling in State Bdelete stateA;delete stateB;delete context;return 0;
}

3.4 命令模式(Command Pattern)

命令模式将请求封装为一个对象,使得用户可以通过不同的命令执行相应的操作。这种模式通常用于将请求和执行解耦的场景。

  • 优点:
    将请求和执行解耦,使得命令可以被传递、排队和撤销。
    方便记录请求和操作历史。
  • 缺点:
    增加了类的数量,系统可能变得复杂。
class Command {
public:virtual void execute() = 0;virtual ~Command() = default;
};class Receiver {
public:void action() {std::cout << "Receiver action" << std::endl;}
};class ConcreteCommand : public Command {
private:Receiver* receiver;public:ConcreteCommand(Receiver* r) : receiver(r) {}void execute() override {receiver->action();}
};class Invoker {
private:Command* command;public:void setCommand(Command* cmd) {command = cmd;}void invoke() {command->execute();}
};int main() {Receiver* receiver = new Receiver();Command* command = new ConcreteCommand(receiver);Invoker* invoker = new Invoker();invoker->setCommand(command);invoker->invoke();  // 输出:Receiver actiondelete command;delete receiver;delete invoker;return 0;
}

3.5 责任链模式(Chain of Responsibility Pattern)

责任链模式通过将请求沿着链传递,直到有对象处理该请求。常用于事件处理和请求分发系统。

  • 优点:
    请求处理逻辑可以动态地组合和扩展。
    可以减少多个条件判断语
class Handler {
protected:Handler* nextHandler;public:Handler() : nextHandler(nullptr) {}virtual void handleRequest() = 0;void setNext(Handler* next) {nextHandler = next;}virtual ~Handler() = default;
};class ConcreteHandlerA : public Handler {
public:void handleRequest() override {std::cout << "Handler A is handling request" << std::endl;if (nextHandler) nextHandler->handleRequest();}
};class ConcreteHandlerB : public Handler {
public:void handleRequest() override {std::cout << "Handler B is handling request" << std::endl;if (nextHandler) nextHandler->handleRequest();}
};int main() {Handler* handlerA = new ConcreteHandlerA();Handler* handlerB = new ConcreteHandlerB();handlerA->setNext(handlerB);handlerA->handleRequest();delete handlerA;delete handlerB;return 0;
}

输出

Handler A is handling request
Handler B is handling request

相关文章:

C++设计模式

C设计模式 什么是 C 设计模式&#xff1f;设计模式的用途设计模式的核心原则设计模式的分类 1. 创建型设计模式1.1 单例模式&#xff08;Singleton Pattern&#xff09;1.2 工厂方法模式&#xff08;Factory Method Pattern&#xff09;1.3 抽象工厂模式&#xff08;Abstract F…...

LM芯片学习

1、LM7805稳压器 https://zhuanlan.zhihu.com/p/626577102?utm_campaignshareopn&utm_mediumsocial&utm_psn1852815231102873600&utm_sourcewechat_sessionhttps://zhuanlan.zhihu.com/p/626577102?utm_campaignshareopn&utm_mediumsocial&utm_psn18528…...

使用 MyBatis-Plus Wrapper 构建自定义 SQL 查询

前言 MyBatis-Plus (MP) 是一款基于 MyBatis 的增强工具&#xff0c;它简化了数据库操作&#xff0c;提供了诸如自动分页、条件构造器等功能&#xff0c;极大地提高了开发效率。其中&#xff0c;Wrapper 条件构造器是 MP 的核心功能之一&#xff0c;它允许开发者以链式调用的方…...

C# OpenCvSharp DNN 实现百度网盘AI大赛-表格检测第2名方案第一部分-表格边界框检测

目录 说明 效果 模型 项目 代码 frmMain.cs YoloDet.cs 参考 下载 其他 说明 百度网盘AI大赛-表格检测的第2名方案。 该算法包含表格边界框检测、表格分割和表格方向识别三个部分&#xff0c;首先&#xff0c;ppyoloe-plus-x 对边界框进行预测&#xff0c;并对置信…...

手分割数据集labelme格式505张1类别

数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;505 标注数量(json文件个数)&#xff1a;505 标注类别数&#xff1a;1 标注类别名称:["hands"] 每个类别标注的框数&#xf…...

2012年西部数学奥林匹克试题(几何)

2012/G1 △ A B C \triangle ABC △ABC 内有一点 P P P, P P P 在 A B AB AB, A C AC AC 上的投影分别为 E E E, F F F, 射线 B P BP BP, C P CP CP 分别交 △ A B C \triangle ABC △ABC 的外接圆于点 M M M, N N N. r r r 为 △ A B C \triangle ABC △ABC 的内…...

GB28181系列三:GB28181流媒体服务器ZLMediaKit

我的音视频/流媒体开源项目(github) GB28181系列目录 目录 一、ZLMediaKit介绍 二、 ZLMediaKit安装、运行(Ubuntu) 1、安装 2、运行 3、配置 三、ZLMediaKit使用 一、ZLMediaKit介绍 ZLMediaKit是一个基于C11的高性能运营级流媒体服务框架&#xff0c;项目地址&#xf…...

【微服务】SpringBoot 整合Redis Stack 构建本地向量数据库相似性查询

目录 一、前言 二、向量数据库介绍 2.1 什么是向量数据库 2.2 向量数据库特点 2.3 向量数据库使用场景 三、常用的向量数据库解决方案 3.1 Milvus 3.1.1 Milvus是什么 3.1.2 Milvus主要特点 3.2 Faiss 3.2.1 Faiss是什么 3.2.2 Faiss主要特点 3.3 Pinecone 3.3.1 …...

神州数码DCME-320 online_list.php存在任意文件读取漏洞

免责声明: 本文旨在提供有关特定漏洞的深入信息,帮助用户充分了解潜在的安全风险。发布此信息的目的在于提升网络安全意识和推动技术进步,未经授权访问系统、网络或应用程序,可能会导致法律责任或严重后果。因此,作者不对读者基于本文内容所采取的任何行为承担责任。读者在…...

Shadcn UI 实战:打造可维护的企业级组件库

"我们真的需要自己写一套组件库吗&#xff1f;"上周的技术评审会上,我正在和团队讨论组件库的选型。作为一个快速发展的创业公司,我们既需要高质量的组件,又想保持灵活的定制能力。在对比了多个方案后,我们选择了 shadcn/ui 这个相对较新的解决方案。 说实话,最开始…...

C#速成(GID+图形编程)

常用类 类说明Brush填充图形形状,画刷GraphicsGDI绘图画面&#xff0c;无法继承Pen定义绘制的对象直线等&#xff08;颜色&#xff0c;粗细&#xff09;Font定义文本格式&#xff08;字体&#xff0c;字号&#xff09; 常用结构 结构说明Color颜色Point在平面中定义点Rectan…...

CMD使用SSH登陆Ubuntu

1.确认sshserver是否安装好 ps -e | grep sshd 450 ? 00:00:00 sshd 2、如果看到sshd那说明ssh-server已经启动了 其实在/etc/ssh下有一个sshd_config 文件。对这个文件进行修改vim sshd_config。 往文件中添加如下内容&#xff1a; Port 22 Protocol 2 PermitRootLogin yes P…...

Fay环境安装及使用

一、项目源码 代码地址 &#xff1a; Fay 2D数字人源码地址&#xff1a;xuniren LLM用是清华开源的ChatGLM源码地址&#xff1a;ChatGLM-6B 模型地址chatglm2-6b-int4 &#xff08;大模型的安装直接参考了我的另一篇文章&#xff1a;ChatGLM2-6B-int4的…...

重写 `equals` 和 `hashCode` 的一致性

重写 equals 和 hashCode 的一致性 在 Java 中&#xff0c;当我们重写 equals 方法时&#xff0c;通常需要同时重写 hashCode 方法&#xff0c;以确保对象在逻辑上相等时&#xff0c;其哈希值也相等。这是一种重要的契约&#xff08;contract&#xff09;&#xff0c;主要用于…...

【游戏设计原理】14 - MDA:游戏的机制、运行和体验

1. 学习、分析并总结 MDA 原理 MDA (Mechanics, Dynamics, and Aesthetics) 是一种用来分析和理解游戏设计的框架&#xff0c;由 Marc LeBlanc, Robin Hunicke, 和 Robert Zubek 提出。这个框架将游戏分解为三个核心要素&#xff1a; Mechanics&#xff08;机制&#xff09;&…...

鸿蒙Next创建自定义组件总结

一、引言 在鸿蒙Next开发中&#xff0c;自定义组件是构建高效、可维护UI的重要组成部分。它具有可组合、可重用以及数据驱动UI更新等特点&#xff0c;能帮助开发者更好地实现代码复用、业务逻辑与UI分离等目标。本文将详细总结创建自定义组件的相关知识&#xff0c;包括其基本…...

redis 缓存使用

工具类 package org.springblade.questionnaire.redis;import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factor…...

Javascript面试手撕常见题目(回顾一)

1.JS查找文章中出现频率最高的单词? 要在JavaScript中查找文章中出现频率最高的单词&#xff0c;你可以按照以下步骤进行操作&#xff1a; 将文章转换为小写&#xff1a;这可以确保单词的比较是大小写不敏感的。移除标点符号&#xff1a;标点符号会干扰单词的计数。将文章拆…...

lc146LRU缓存——模仿LinkedHashMap

146. LRU 缓存 - 力扣&#xff08;LeetCode&#xff09; 法1&#xff1a; 调用java现有的LinkedHashMap的方法&#xff0c;但不太理解反正都不需要扩容&#xff0c;super(capacity, 1F, true);不行吗&#xff0c;干嘛还弄个装载因子0.75还中途扩容一次浪费时间。 class LRUC…...

【C语言】头文件

所有学习过C语言的朋友都熟悉这样一段代码&#xff1a; #include <stdio.h>int main(int argc, char *argv[]) {return 0; }那么&#xff0c;你真的了解 <stdio.h> 吗&#xff1f; <stdio…...

WSL (Windows Subsystem for Linux)

文章目录 Windows下使用Linux的三种方式&#xff1a;1.WSL(1)安装WSL(2)初始化Linux系统(3)安装、创建、激活 Python虚拟环境 2.虚拟机3.Docker Windows下使用Linux的三种方式&#xff1a; 1.WSL 是最简单的在 Windows 上运行 Linux 环境的方式&#xff0c;适用于日常开发和命…...

[Java] 使用 VSCode 来开发 Java

目录 前言Java 环境怎么看自己是否已经配置完成&#xff1f;安装 JDK安装 Maven 环境修改 Maven 依赖源 完善 VS Code配置插件配置 Maven配置 Maven Settings配置 Maven 可执行文件地址 前言 由于使用 VSCode 编码已经成为习惯&#xff0c;并且它确实相对其他的 IDE 较为轻量化…...

机器学习之偏差

机器学习中的偏差&#xff08;Bias&#xff09;是指模型的预测值与真实值之间的系统性误差&#xff0c;或者说模型无法准确捕捉数据中复杂模式的能力。偏差通常与模型的假设或学习能力有关&#xff0c;过高的偏差会导致模型的性能不佳&#xff0c;表现为欠拟合。 偏差的来源 模…...

微信小程序处理交易投诉管理,支持多小程序

大家好&#xff0c;我是小悟 1、问题背景 玩过微信小程序生态的&#xff0c;或许就有这种感受&#xff0c;如果收到投诉单&#xff0c;不会及时通知到手机端&#xff0c;而是每天早上10:00向小程序的管理员及运营者推送通知。通知内容为截至前一天24时该小程序账号内待处理的交…...

在C#中测试比较目录的不同方法以查看它们有哪些共同的文件

C# 中的示例“比较目录以查看它们有哪些共同的文件”使用Directory.GetFiles获取两个目录中的文件。它对文件进行排序&#xff0c;并比较两个排序后的列表以查看哪些文件位于第一个目录中、第二个目录中或两个目录中。有关其工作原理的详细信息&#xff0c;请参阅该示例。 Kur…...

2D gaussian splatting的配置和可视化

继3D gaussian splatting&#xff0c;2D gaussian splatting除了渲染新视角&#xff0c;还能够生成mesh模型。 2D gaussian splatting的配置 两者的运行环境基本一致 GitHub - hbb1/2d-gaussian-splatting: [SIGGRAPH24] 2D Gaussian Splatting for Geometrically Accurate …...

git分支管理

目录 1.Git分支管理1.1 分支创建1.2 分支删除1.3 分支合并1.4 分支的本质1.5 分支的冲突 2.Git stash2.1 git stash 3.分支管理策略3.1主分支3.2辅助分支3.3Feature分支3.4release分支3.5bugfix分支 1.Git分支管理 Git 的默认分支就是 master。你所作的commit会在master分支上…...

【Elasticsearch入门到落地】4、Elasticsearch的安装

接上篇《3、es与mysql的概念对比》 上一篇我们学习了Elasticsearch与Mysql的概念与区别。本篇我们来进行Elasticsearch的环境准备及软件安装。 一、环境准备 如果我们没有自己的Linux服务器&#xff0c;且现在正在使用的是Windows操作系统的电脑&#xff0c;那么首先我们需要安…...

如何在谷歌浏览器中开启安全浏览

在数字化时代&#xff0c;网络安全变得愈发重要。作为全球最受欢迎的网络浏览器之一&#xff0c;谷歌浏览器提供了多种功能来保护用户的在线安全。本文将详细介绍如何在谷歌浏览器中开启安全浏览&#xff0c;并额外提供一些有用的页面滚动设置、地址栏快捷搜索和跟踪防护的相关…...

短视频矩阵贴牌:打造品牌新势力的策略与实践

在数字化浪潮席卷全球的今天&#xff0c;短视频以其独特的魅力迅速崛起&#xff0c;成为连接用户与品牌的重要桥梁。企业为了快速抢占市场&#xff0c;提升品牌影响力&#xff0c;纷纷探索短视频矩阵贴牌这一新兴模式。本文将深入探讨短视频矩阵贴牌的概念、优势、实施流程及注…...

【潜意识Java】javaee中的SpringBoot在Java 开发中的应用与详细分析

目录 一、前言 二、Spring Boot 简介 三、Spring Boot 核心模块 四、Spring Boot 项目实战&#xff1a;构建一个简单的 RESTful API 1. 创建 Spring Boot 项目 2. 配置数据库 3. 创建实体类 4. 创建 JPA 仓库接口 5. 创建服务层 6. 创建控制器层 7. 测试 API 8. 运…...

linux basics

本篇文章旨在为网络安全初学者介绍linux操作系统基础。通过阅读本文&#xff0c;读者将能够对linux系统有一个初步的了解 一、openssl 1、命令&#xff1a; openssl passwd -1 123 -l参数指定使用MD5加密算法对密码"123"进行加密处理。MD5是一种常用的哈希算法,它将…...

[OpenGL] Transform feedback 介绍以及使用示例

一、简介 本文介绍了 OpenGL 中 Transform Feedback 方法的基本概念和代码示例。 二、Transform Feedback 介绍 1. Transform Feedback 简介 根据 OpenGL-wiki&#xff0c;Transform Feedback 是捕获由顶点处理步骤&#xff08;vertex shader 和 geometry shader&#xff0…...

pytorch_fid 安装笔记

目录 torch安装&#xff1a; pytorch_fid安装 torch安装&#xff1a; pip install torch2.5.0 --index-url https://download.pytorch.org/whl/cu121 pytorch_fid安装 pip install pytorch_fid 安装后&#xff0c;torch也会自动安装&#xff0c;导致torch引用报错。...

SAM大模型实践(一)

参考着segment-geospatial 项目主页的介绍&#xff0c;尝试复现一下Example-satallite的案例。 Satellite - segment-geospatialhttps://samgeo.gishub.org/examples/satellite/ 过程当中遇到了一些坑给大家做点分享&#xff0c;主要有几种情况&#xff0c;一个是torch…...

数据结构 ——前缀树查词典的实现

数据结构 ——前缀树查词典的实现 一、前缀树的概念 前缀树是一种多叉树结构&#xff0c;主要用于存储字符串。每个节点代表一个字符&#xff0c;路径从根节点到叶节点表示一个完整的字符串。前缀树的关键特征是 共享前缀&#xff0c;也就是说&#xff0c;如果两个字符串有相…...

边缘智能创新应用大赛获奖作品系列一:智能边缘计算✖软硬件一体化,开启全场景效能革命新征程

边缘智能技术快速迭代&#xff0c;并与行业深度融合。它正重塑产业格局&#xff0c;催生新产品、新体验&#xff0c;带动终端需求增长。为促进边缘智能技术的进步与发展&#xff0c;拓展开发者的思路与能力&#xff0c;挖掘边缘智能应用的创新与潜能&#xff0c;高通技术公司联…...

修改ubuntu apt 源及apt 使用

视频教程:修改ubuntu apt 源和apt 使用方法_哔哩哔哩_bilibili 1 修改apt源 1.1 获取阿里云ubuntu apt 源 https://developer.aliyun.com/mirror/ubuntu?spma2c6h.13651102.0.0.3e221b11mqqLBC 1.2 修改apt 源 vim /etc/apt/sources.list deb https://mirrors.aliyun.com/ub…...

Kafka 磁道寻址过程详解

前言 Apache Kafka 是一款高吞吐、分布式的消息流平台&#xff0c;广泛应用于实时数据处理和事件驱动系统。在 Kafka 中&#xff0c;消息是存储在磁盘上的&#xff0c;这种高效的数据读写性能得益于 Kafka 独特的磁盘存储架构和寻址机制。本文将从 Kafka 的存储结构、磁道寻址…...

GEE+本地XGboot分类

GEE本地XGboot分类 我想做提取耕地提取&#xff0c;想到了一篇董金玮老师的一篇论文&#xff0c;这个论文是先提取的耕地&#xff0c;再做作物分类&#xff0c;耕地的提取代码是开源的。 但这个代码直接在云端上进行分类&#xff0c;GEE会爆内存&#xff0c;因此我准备把数据下…...

安防监控Liveweb视频汇聚融合平台助力执法记录仪高效使用

Liveweb平台可接入的设备除了常见的智能分析网关与摄像头以外 &#xff0c;还可通过GB28181协议接入执法记录仪&#xff0c;实现对执法过程的全程监控与录像&#xff0c;并对执法轨迹与路径进行调阅回看。那么&#xff0c;如何做到执法记录仪高效使用呢&#xff1f; 由于执法记…...

酷盾安全:Edge SCDN边缘安全内容分发网络

在当今数字化迅猛发展的时代&#xff0c;互联网内容分发的高效与安全成为了企业不可忽视的重要课题。为了满足这一需求&#xff0c;酷盾安全推出了创新的Edge Secure Content Delivery Network&#xff08;Edge Scdn&#xff09;解决方案&#xff0c;它不仅融合了分布式DDoS防护…...

决策引擎技术

决策引擎&#xff08;Decision Engine&#xff09;是一种用于自动化决策过程的软件系统。它通常用于处理复杂的业务逻辑&#xff0c;根据输入的数据和预定义的规则或模型来做出决策。决策引擎在许多领域都有广泛的应用&#xff0c;如金融、保险、医疗、供应链管理等。 在Java中…...

Servlet学习中遇到的一些问题及解决

错误&#xff1a;JavaWeb-错误&#xff1a;类xxx不是Servlet 解决&#xff1a;可能是Tomcat版本不匹配导致&#xff0c;更换Tomcat版本解决问题 错误&#xff1a;在自定义的Servlet类中不能添加 WebServlet 注解 解决&#xff1a;可能是WebServlet版本不匹配&#xff0c;更换…...

oracle开窗函数笔记、over()笔记

文章目录 开窗函数、组函数、分析函数概念聚合函数和分析函数的区别partition by后面也可以跟多个字段 开窗函数一定要加 聚合函数、或分析函数吗&#xff0c;否则会报错lag()和lead()的用法lag和lead实战开窗函数可以和其他函数一起使用吗? TODO开窗函数中的count(1)是什么意…...

深度学习面试相关-2024.12.15记录

深度学习 面试相关- 2024.12.15记录 目录 深度学习 面试相关- 2024.12.15记录整体常问问题1数学基础1.1 概率统计1.2 线代 2机器学习算法2.1 深度学习算法2.2 机器学习算法 整体常问问题 https://www.nowcoder.com/discuss/353154899112304640 1数学基础 1.1 概率统计 htt…...

CSS|07 标准文档流

标准文档流 一、什么是标准文档流 在制作的 HTML 网页和 PS 画图软件画图时有本质上面的区别: HTML 网页在制作的时候都得遵循一个“流的规则:从左至右、从上至下。 使用 Ps 软件画图时可以在任意地方画图。 <!DOCTYPE html> <html lang"en"> <hea…...

1 JVM JDK JRE之间的区别以及使用字节码的好处

JDK jdk是编译java源文件成class文件的&#xff0c;我们使用javac命令把java源文件编译成class文件。 我们在java安装的目录下找到bin文件夹&#xff0c;如下图所示: 遵循着编译原理&#xff0c;把java源文件编译成JVM可识别的机器码。 其中还包括jar打包工具等。主要是针对…...

ubuntu安装8812au驱动却无法加载网卡的问题

驱动GIT地址 https://github.com/aircrack-ng/rtl8812au按照里面提示安装驱动 输入 sudo dkms status查看驱动是否安装成功 接入网卡&#xff0c;看看ifconfig能否输出网卡 如果不行 使用sudo dmesg -w插拔网卡看看输出 如果输出为: load module with unavailable key is …...

Eureka学习笔记-服务端

Eureka学习笔记 服务端 模块设计 Resources &#xff1a;这部分对外暴露了一系列的 Restful 接口。Eureka Client 的注册、心跳、获取服务列表等操作都需要调用这些接口。另外&#xff0c;其他的 Server 在同步 Registry 时也需要调用这些接口。Controller &#xff1a;这里提…...