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

C++ 设计模式 —— 组合模式

C++ 设计模式 —— 组合模式

在这里插入图片描述

0. 引用连接

本文主要的思路和代码,来自于对以下连接的学习和实现:

组合模式

1. 引言

1.1 什么是组合模式?

  • 组合模式的定义
  • 组合模式的作用

组合模式是一种行为型设计模式,它将对象组合成树形结构以表示部分 - 整体的层次结构。这种模式使得用户对单个对象和组合对象的使用具有一致性。组合模式主要应用于需要表示复杂对象结构或者需要将对象组合成树形结构的场景。
组合模式的定义和作用:
定义:组合模式通过一种巧妙的设计方案,可以一致性地处理整个树形结构或者树形结构的一部分,也可以一致性地处理树形结构中的叶子节点(不包含子节点的节点)和容器节点。
作用:组合模式主要解决了在对象组合树中,如何实现一致性的操作和处理的问题。它使得用户可以方便地对对象树进行操作,而不需要考虑对象的具体类型。组合模式还提供了一种灵活的方式来表示对象结构,可以方便地添加和删除对象。

1.2 组合模式与其他设计模式的关系

组合模式是行为型设计模式的一种,它将对象组合成树形结构以表示部分 - 整体的层次结构。在实际应用中,组合模式与其他设计模式有着紧密的联系,常常共同出现在同一个解决方案中。以下是组合模式与其他设计模式的一些关系:

  1. 装饰者模式 : 装饰者模式与组合模式在结构上有相似之处,但它们的目的不同。装饰者模式通过动态地给一个对象添加职责,使其具有更多的功能,而组合模式关注的是将对象组合成树形结构以表示部分 - 整体的层次结构。两者都依赖于递归组合来组织大量对象。在某些情况下,装饰者模式和组合模式可以结合使用,以实现更加灵活的对象结构。
  2. 责任链模式 : 责任链模式用于处理具有多个处理步骤的问题,它将请求沿着处理器链进行传递。组合模式则关注将对象组合成树形结构以表示部分 - 整体的层次结构。虽然这两个模式的用途不同,但它们可以结合使用。例如,可以使用组合模式构建一个复杂的对象结构,然后使用责任链模式处理该结构中的请求。
  3. 迭代器模式 : 迭代器模式允许在不暴露底层数据结构的情况下遍历和访问数据。在组合模式中,可以使用迭代器来遍历复合对象的子元素。迭代器模式抽象了遍历组件的过程,确保每个元素都被访问到,同时不暴露底层数据结构的细节。
  4. 访问者模式 : 访问者模式允许在不改变对象结构的前提下定义新的操作。在组合模式中,可以将访问者模式应用于复合结构,以便在不更改现有类层次结构的情况下对元素执行操作。访问者模式使您可以在现有代码中添加新行为,而无需修改现有代码。
    总之,在实际软件开发中,设计模式往往不会孤立存在。组合模式与其他设计模式之间的紧密联系使得开发人员可以根据具体需求和场景,将这些模式结合使用,以实现更加灵活、高效和可扩展的软件系统。

1.3 组合模式适用的场景

组合模式是一种行为型设计模式,适用于多种场景,如树形对象结构、统一对象处理、动态责任、可变责任和 UI 工具包等。在实际应用中,组合模式与其他设计模式密切相关,共同解决各种问题。以下是组合模式与其他设计模式的一些关系:

  1. 树形对象结构 : 组合模式适用于实现树形对象结构,如组织结构、文件系统、UI 元素等。这种结构可以方便地表示部分 - 整体的层次关系。在组合模式中,对象通过递归组合形成树状结构,使得客户代码可以统一处理简单元素和复杂元素。
  2. 统一对象处理 : 组合模式允许客户代码以统一的方式处理简单元素和复杂元素。这种统一处理方式可以简化客户端代码,提高代码的可维护性和可扩展性。通过组合模式,客户端可以忽略对象的复杂内部结构,而仅关注对象的整体行为。
  3. 动态责任 : 组合模式允许在运行时动态地为单个对象添加责任,而无需修改现有代码。这种动态责任分配可以提高系统的灵活性,使其能够适应不断变化的需求。在组合模式中,可以通过将新的责任分配给现有的对象来实现动态责任。
  4. 可变责任 : 组合模式适用于责任可能随时间变化的场景。在组合模式中,对象可以具有不同的责任,这使得系统能够适应不断变化的需求。通过组合模式,可以轻松地为对象添加新的责任,而无需修改现有代码。
  5. UI 工具包 : 组合模式在 UI 工具包中具有广泛的应用。在这种场景下,顶级 UI 元素由许多较小的独立底层 UI 元素组成,这些元素都响应相同的事件和操作。通过使用组合模式,可以轻松地管理 UI 元素的层次结构,并确保它们以一致的方式响应事件。
  6. 计费系统 : 在计费系统中,组合模式可以应用于处理复杂的活动记录。在这种场景下,重要的是能够生成正确的计费,而不关心活动的具体细节。通过使用组合模式,可以将复杂的活动记录组织成一个树形结构,以便生成正确的计费。
    组合模式与其他设计模式密切相关,它们共同解决各种实际问题。在实际应用中,可以根据具体需求和场景,将组合模式与其他设计模式结合使用,以实现更加灵活、高效和可扩展的软件系统。

2. 组合模式的实现

2.1 组合模式概念伪代码

2.1.1 图形概念组合伪代码

CompoundGraphic 类是一个容器,可以包含任意数量的子形状,包括其他复合形状。复合形状具有与简单形状相同的方法。但是,与简单形状不同,复合形状会将请求递归地传递给所有子项,并将结果“求和”。
客户端代码通过与所有形状共享的单一接口与所有形状进行交互。因此,客户端不知道自己正在处理简单形状还是复合形状。客户端可以在不与组成该结构的具体类耦合的情况下处理非常复杂的对象结构。

代码结构分析:

  1. 定义复合图形类,包含初始化方法和递归调用方法。
  2. 定义简单图形类,包含初始化方法和基本操作方法。
  3. 定义客户端代码,通过与所有形状共享的单一接口与所有形状进行交互。
  4. 在客户端代码中,根据需要创建复合图形对象和简单图形对象。
  5. 使用复合图形对象和简单图形对象执行各种操作,如添加、删除、修改等。
  6. 验证客户端代码是否正确处理了复合图形对象和简单图形对象的操作。
// The component interface declares common operations for both
// simple and complex objects of a composition.
interface Graphic ismethod move(x, y)method draw()// The leaf class represents end objects of a composition. A
// leaf object can't have any sub-objects. Usually, it's leaf
// objects that do the actual work, while composite objects only
// delegate to their sub-components.
class Dot implements Graphic isfield x, yconstructor Dot(x, y) { ... }method move(x, y) isthis.x += x, this.y += ymethod draw() is// Draw a dot at X and Y.// All component classes can extend other components.
class Circle extends Dot isfield radiusconstructor Circle(x, y, radius) { ... }method draw() is// Draw a circle at X and Y with radius R.// The composite class represents complex components that may
// have children. Composite objects usually delegate the actual
// work to their children and then "sum up" the result.
class CompoundGraphic implements Graphic isfield children: array of Graphic// A composite object can add or remove other components// (both simple or complex) to or from its child list.method add(child: Graphic) is// Add a child to the array of children.method remove(child: Graphic) is// Remove a child from the array of children.method move(x, y) isforeach (child in children) dochild.move(x, y)// A composite executes its primary logic in a particular// way. It traverses recursively through all its children,// collecting and summing up their results. Since the// composite's children pass these calls to their own// children and so forth, the whole object tree is traversed// as a result.method draw() is// 1. For each child component://     - Draw the component.//     - Update the bounding rectangle.// 2. Draw a dashed rectangle using the bounding// coordinates.// The client code works with all the components via their base
// interface. This way the client code can support simple leaf
// components as well as complex composites.
class ImageEditor isfield all: CompoundGraphicmethod load() isall = new CompoundGraphic()all.add(new Dot(1, 2))all.add(new Circle(5, 3, 10))// ...// Combine selected components into one complex composite// component.method groupSelected(components: array of Graphic) isgroup = new CompoundGraphic()foreach (component in components) dogroup.add(component)all.remove(component)all.add(group)// All components will be drawn.all.draw()

2.1.2 叶子组合伪代码

组合模式是使用抽象基类或接口Component实现的,它声明了公共操作。两个具体类LeafComposite继承自Component。以下是这些概念的伪代码描述:

class Component {
public:virtual void Add(Component a) { }virtual void Remove() { }virtual void Delete(Component a) { }
};class Leaf : public Component {
public:void Add(Component a) {cout << "something is added to the leaf" << endl;}void Remove() {cout << "something is removed from the leaf" << endl;}void Delete(Component a) {cout << "something is deleted from leaf" << endl;}
};class Composite : public Component {vector<Component> compositeComponents;
public:void AddElement(Component a) {compositeComponents.push_back(a);}void Add(Component a) {cout << "something is added to the composite" << endl;}void Remove() {cout << "something is removed from the composite" << endl;}void Delete(Component a) {cout << "something is deleted from the composite";}
};

在这个伪代码中,Component是一个抽象基类,具有三个方法:AddRemoveDeleteLeafComposite类继承自Component并实现这些方法。Composite类还包含一个表示其子组件的Component对象向量¹。

这种结构允许您统一处理单个对象(Leaf)和对象的组合(Composite)。

3. 组合模式的优点和缺点

Composite 模式的优点

  • 它简化了与复合结构中对象交互的客户端代码。
  • 它使得向复合结构添加新功能变得容易。
  • 它使得表示分层数据结构变得容易。

Composite 模式的缺点

  • 它可能会使复合对象的代码比简单对象的代码更复杂。
  • 如果复合结构包含大量的子对象,它可能会降低复合结构的性能。

4. 代码实现

4.1 真实案例伪代码描述

Composite 模式的真实案例是树形数据结构,例如目录树。在这种情况下,抽象部分将表示一个目录,具体部分将表示文件或其他目录。以下是使用组合模式的伪代码示例:

# 抽象部分
class Directory:def add_file(self, file):passdef remove_file(self, file):passdef list_files(self):pass# 具体部分
class File:def __init__(self, name):self.name = nameclass DirectoryNode:def __init__(self, directory):self.directory = directoryself.children = []def add_child(self, child):self.children.append(child)def remove_child(self, child):self.children.remove(child)def list_children(self):for child in self.children:print(child.name)# 客户端代码
directory = Directory()
file1 = File("file1.txt")
file2 = File("file2.txt")
directory_node = DirectoryNode(directory)
directory_node.add_child(file1)
directory_node.add_child(file2)
directory.list_files()  # 输出:file1.txt, file2.txt

在上述代码中,Directory类是抽象部分,它定义了目录的基本操作,如添加文件、删除文件和列出文件。File类是具体部分,表示一个文件对象。DirectoryNode类是具体部分的组合体,它包含一个Directory对象和一个子节点列表。通过调用add_childremove_child方法,可以向目录树中添加或删除子节点。最后,客户端代码创建了一个目录对象和两个文件对象,并将这两个文件对象作为子节点添加到目录节点中。然后,通过调用list_files方法,列出了目录中的所有文件。

4.2 概念示例代码

#include <iostream>class Component {public:virtual void operation() = 0;
};class Leaf : public Component {public:void operation() override {std::cout << "I am a leaf." << std::endl;}
};class Composite : public Component {public:void operation() override {std::cout << "I am a composite." << std::endl;for (auto& child : children) {child->operation();}}

这段代码展示了组合模式的实现。组合模式是一种结构型设计模式,它允许将对象组织成树形结构,使得客户端可以以统一的方式处理单个对象和组合对象。

代码中定义了一个抽象基类Component,其中包含一个纯虚函数operation()。这个函数在子类中被重写,用于执行具体的操作。

接下来定义了两个子类:LeafCompositeLeaf类表示叶子节点,它从Component类继承,并重写了operation()函数,输出"I am a leaf.“。Composite类表示复合节点,它也从Component类继承,并重写了operation()函数。在这个函数中,首先输出"I am a composite.”,然后通过循环遍历子节点(children),对每个子节点调用operation()函数。

通过组合模式,可以将叶子节点和复合节点统一对待,无论它们是单独使用还是作为其他节点的一部分。这种灵活性使得代码更加可扩展和易于维护。

4.2.1 2.1.1 概念代码实际代码

#include <iostream>
#include <vector>class Graphic {
public:virtual void move(int x, int y) = 0;virtual void draw() = 0;
};class Dot : public Graphic {
protected:int x, y;
public:Dot(int x, int y) : x(x), y(y) {}void move(int x, int y) override {this->x += x; this->y += y;}void draw() override {std::cout << "Draw a dot at " << x << " and " << y << std::endl;}
};class Circle : public Dot {
protected:int radius;
public:Circle(int x, int y, int radius) : Dot(x, y), radius(radius) {}void draw() override {std::cout << "Draw a circle at " << x << " and " << y << " with radius " << radius << std::endl;}
};class CompoundGraphic : public Graphic {
protected:std::vector<Graphic*> children;
public:void add(Graphic* child) {children.push_back(child);}void remove(Graphic* child) {children.erase(std::remove(children.begin(), children.end(), child), children.end());}void move(int x, int y) override {for (Graphic* child : children)child->move(x, y);}void draw() override {for (Graphic* child : children)child->draw();// Draw a dashed rectangle using the bounding coordinates.// This part is left as an exercise.}
};class ImageEditor {
protected:CompoundGraphic* all;
public:void load() {all = new CompoundGraphic();all->add(new Dot(1, 2));all->add(new Circle(5, 3, 10));// ...}void groupSelected(std::vector<Graphic*> components) {CompoundGraphic* group = new CompoundGraphic();for (Graphic* component : components) {group->add(component);all->remove(component);}all->add(group);all->draw();}
};

这段代码定义了一个抽象基类Component,其中包含三个方法:AddRemoveDeleteLeafComposite类继承自Component并实现了这些方法。Composite类还包含一个Component指针的向量,表示其子组件。这种结构允许您统一处理单个对象(Leaf)和对象的组合(Composite)。

需要注意的是,这段代码是Composite Pattern的基本实现,并没有包含任何特定的功能。需要用自己逻辑替换占位符方法。同时,请记住在使用C++中的原始指针时正确管理内存。如果适用,可以考虑使用智能指针。

我们可以在任何支持C++11或更高版本的C++环境中编译和运行此代码。如果需要想查看这些方法的输出,需要创建LeafComposite的实例,调用它们的方法,并将输出打印到控制台。

4.3 真实案例代码

4.3.1 geom_exmaple.h
#ifndef _GEOM_EXAMPLE_H_
#define _GEOM_EXAMPLE_H_#include <vector>// The component interface declares common operations for both
// simple and complex objects of a composition.
class Graphic
{
public:virtual void move(int x, int y) = 0;virtual void draw() = 0;
};// The leaf class represents end objects of a composition. A
// leaf object can't have any sub-objects. Usually, it's leaf
// objects that do the actual work, while composite objects only
// delegate to their sub-components.
class Dot : public Graphic
{
protected:int x, y;public:Dot(int x, int y);void move(int x, int y) override;void draw() override;
};// All component classes can extend other components.
class Circle : public Dot
{
private:int radius;public:Circle(int x, int y, int radius);void draw() override;
};// The composite class represents complex components that may
// have children. Composite objects usually delegate the actual
// work to their children and then "sum up" the result.
class CompoundGraphic : public Graphic
{
private:std::vector<Graphic*> children;public:void add(Graphic* child);void remove(Graphic* child);void move(int x, int y) override;void draw() override;
};// The client code works with all the components via their base
// interface. This way the client code can support simple leaf
// components as well as complex composites.
class ImageEditor
{
private:CompoundGraphic all;public:void load();// Combine selected components into one complex composite// component.void groupSelected(std::vector<Graphic*> components);
};class GeomCompositeTest
{
public:static void GeomCompositeExample();
};#endif // _GEOM_EXAMPLE_H_
4.3.2 geom_example.cpp
#include "geom_example.h"#include <iostream>Dot::Dot(int x, int y): x(x), y(y)
{
}void Dot::move(int x, int y)
{this->x += x;this->y += y;
}void Dot::draw()
{std::cout << "Draw a dot at (" << x << ", " << y << ")." << std::endl;
}Circle::Circle(int x, int y, int radius): Dot(x, y), radius(radius)
{
}void Circle::draw()
{std::cout << "Draw a circle at (" << x << ", " << y << ") with radius " << radius << "." << std::endl;
}void CompoundGraphic::add(Graphic* child)
{children.push_back(child);
}void CompoundGraphic::remove(Graphic* child)
{for (auto it = children.begin(); it != children.end(); ++it) {if (*it == child) {children.erase(it);break;}}
}void CompoundGraphic::move(int x, int y)
{for (Graphic* child : children) {child->move(x, y);}
}void CompoundGraphic::draw()
{std::cout << "1. For each child component:" << std::endl;for (Graphic* child : children) {child->draw(); // Draw the component.// Update the bounding rectangle. (Not shown in the code.)}std::cout << "2. Draw a dashed rectangle using the bounding coordinates." << std::endl;
}void ImageEditor::load()
{all = CompoundGraphic();all.add(new Dot(1, 2));all.add(new Circle(5, 3, 10));// ...
}void ImageEditor::groupSelected(std::vector<Graphic*> components)
{CompoundGraphic group;for (Graphic* component : components) {group.add(component);all.remove(component);}all.add(&group);// All components will be drawn.all.draw();
}void GeomCompositeTest::GeomCompositeExample()
{ImageEditor editor;editor.load();std::vector<Graphic*> components;components.push_back(new Dot(1, 2));components.push_back(new Circle(5, 3, 10));components.push_back(new Dot(7, 8));components.push_back(new Circle(10, 11, 20));editor.groupSelected(components);
}

4.4 代码分析

4.4.1 概念代码分析
4.4.1.1 4.2.1 代码分析

提供的C++代码是组合模式的实现,组合模式是一种设计模式,用于将一组对象以与单个对象的相同方式处理。组合模式的概念允许您将对象组合成树形结构,以表示部分-整体层次结构。

在此代码中,我们有以下类:

  • Component:这是一个抽象基类,声明了简单和复杂对象的组合的共同操作。它声明了一个纯虚函数operation()

  • Leaf:这个类代表组合的结束对象(叶子对象)。它从Component类继承并实现了operation()方法。在这个方法中,它只是打印出"I am a leaf."。

  • Composite:这个类代表可能有子对象的复杂组件。它也从Component类继承并实现了operation()方法。在这个方法中,它首先打印出"I am a composite.",然后遍历其子组件并调用它们的operation()方法。

这种结构允许您统一对待单个对象(Leaf)和对象的组合(Composite)。您可以对所有复合对象执行的操作通常具有最低公共分母关系。

请注意,这段代码是不完整的。Composite类应该包含一个容器(如向量或列表)来保存其子组件,并提供添加或删除子组件的方法。此外,代码目前缺少与之交互的客户端。

4.4.1.2 4.2.2 代码分析

提供的C++代码是组合模式的一个实现,组合模式是一种设计模式,用于在需要以单个对象的方式处理一组对象的情况。组合模式的概念是允许您将对象组合成树形结构,以表示部分-整体层次结构。

在此代码中,我们有以下几个类:

  • Component:这是一个抽象基类,声明了简单和复杂对象的共同操作。它声明了一个纯虚函数operation()。它还具有设置和获取组件父级的方法和添加或删除子组件的方法。

  • Leaf:这个类代表组合的结束对象(叶子对象)。它从Component类继承并实现了operation()方法。在此方法中,它只是打印出"I am a leaf."。

  • Composite:这个类代表可能有子组件的复杂组件。它也从Component类继承并实现了operation()方法。在此方法中,它首先打印出"I am a composite.",然后遍历其子组件并调用它们的operation()方法。

ClientCode函数接受一个Component对象并调用其operation()方法。ClientCode2函数接受两个Component对象。如果第一个是一个复合对象,它将第二个添加为其子对象。然后它调用第一个的operation()方法。

CompositeConceptionalExample函数演示了如何使用这些类。它创建了一个简单的叶子组件和一个包含叶子节点和复合节点的复合树,然后将它们传递给客户端代码。

请注意,此代码未正确管理内存。它使用new创建了几个对象,但没有使用delete删除它们。在现实世界的代码中,应始终记住使用delete删除用new创建的对象,以防止内存泄漏。如果适用,请考虑使用智能指针。

4.4.2 真实案例代码分析

提供的代码是C++中组合模式的一个实现,它用于统一处理单个对象和对象的组成。代码分为两个文件:geom_example.h(头文件)和geom_example.cpp(实现文件)。

geom_example.h中,我们有以下几个类:

  • Graphic:这是一个抽象基类,声明了组合中简单和复杂对象的常见操作。它声明了两个纯虚函数:move(int x, int y)draw()
  • Dot:这个类代表组合的结束对象(叶子对象)。它从Graphic类继承并实现了move(int x, int y)draw()方法。
  • Circle:这个类扩展了Dot类,代表一个更复杂的对象,也可以是组合的一部分。它重写了Dot类中的draw()方法。
  • CompoundGraphic:这个类代表可能具有子组件的复杂组件。它也从Graphic类继承并实现了add(Graphic* child)remove(Graphic* child)move(int x, int y)draw()方法。
  • ImageEditor:这个类通过其基接口与所有组件一起工作。它具有加载组件和将选定的组件组合成一个复杂复合组件的方法。

geom_example.cpp中,这些类被实现:

  • DotCircle类有构造函数来初始化它们的特性,它们实现了在Graphic接口中声明的move(int x, int y)draw()方法。
  • CompoundGraphic类实现了添加或删除子组件、移动所有子组件和绘制所有子组件的方法。
  • ImageEditor类将组件加载到复合对象中,将选定的组件组合成一个新的复合对象,从旧的复合对象中删除它们,将新的复合对象添加到旧的复合对象中,并绘制所有组件。

这段代码演示了如何使用组合模式统一处理单个对象(DotCircle)和对象的组成(CompoundGraphic)。

个人格言

追寻与内心共鸣的生活,未来会逐渐揭晓答案。

Pursue the life that resonates with your heart, and the future will gradually reveal the answer.

在这里插入图片描述

相关文章:

C++ 设计模式 —— 组合模式

C 设计模式 —— 组合模式 0. 引用连接 本文主要的思路和代码&#xff0c;来自于对以下连接的学习和实现&#xff1a; 组合模式 1. 引言 1.1 什么是组合模式&#xff1f; 组合模式的定义组合模式的作用 组合模式是一种行为型设计模式&#xff0c;它将对象组合成树形结构以…...

华为云Stack的学习(九)

十、华为云Stack灾备服务介绍 1.云硬盘备份VBS 云硬盘备份服务&#xff08;VBS&#xff0c;Volume Backup Service&#xff09;可为云硬盘&#xff08;EVS&#xff0c;Elastic Volume Service&#xff09;创建备份&#xff0c;利用备份数据恢复云硬盘&#xff0c;最大限度保障…...

Flink中jobmanager、taskmanager、slot、task、subtask、Parallelism的概念

场景 一个工厂有三个车间每个车间两条生产线 生产流程如下 原料->加工->过滤->分类->美化->包装->下线 JobManager&#xff1a;工厂 在上述场景中&#xff0c;工厂就是jobManager&#xff0c;负责协调、调度和监控整个生产过程 TaskManager&#xff1a;车间…...

OpenHarmony docker环境搭建

OpenHarmony docker环境搭建 要求一台安装ubuntu的虚拟机,vscode软件 安装docker 在 Ubuntu 上安装 Docker 非常直接。我们将会启用 Docker 软件源&#xff0c;导入 GPG key&#xff0c;并且安装软件包。 首先&#xff0c;更新软件包索引&#xff0c;并且安装必要的依赖软件…...

【计算机网络】网络编程接口 Socket API 解读(11)

Socket 是网络协议栈暴露给编程人员的 API&#xff0c;相比复杂的计算机网络协议&#xff0c;API 对关键操作和配置数据进行了抽象&#xff0c;简化了程序编程。 本文讲述的 socket 内容源自 Linux man。本文主要对各 API 进行详细介绍&#xff0c;从而更好的理解 socket 编程。…...

Qt工具开发,该不该跳槽?

Qt工具开发&#xff0c;该不该跳槽? 就这样吧&#xff0c;我怕你跳不动。 嵌入式UI&#xff0c;目前趋势是向着LVGL发展。QT已经在淘汰期了。很多项目还在用&#xff0c;但技术上已经落后。QT短期内不会全面淘汰&#xff0c;但退位让贤的大趋势已经很清楚了。 最近很多小伙伴…...

【深度学习】DDPM,Diffusion,概率扩散去噪生成模型,原理解读

看过来看过去&#xff0c;唯有此up主&#xff0c;非常牛&#xff1a; Video Explaination(Chinese) 1. DDPM Introduction q q q - 一个固定&#xff08;或预定义&#xff09;的正向扩散过程&#xff0c;逐渐向图像添加高斯噪声&#xff0c;直到最终得到纯噪声。 p θ p_θ p…...

HT8699:内置 BOOST 升Y双声道音频功率放大器

HT8699是一款内置BOOST升Y模块的立体声音频功率放大器。HT8699具有AB类和D类切换功能&#xff0c;在受到D类功放EMI干扰困扰时&#xff0c;可切换至AB类音频功放模式。 在D类模式下&#xff0c;内置的BOOST升Y模块可通过外置电阻调节升Y值&#xff0c;即使是锂电池供电&#xf…...

利达卓越:关注环保事业,持续赋能科技

随着全球环境问题的日益突出,绿色金融作为一种新兴的金融模式逐渐受到各国的重视。绿色金融是指在金融活动中,通过资金、信贷和风险管理等手段,支持环境友好和可持续发展的项目和产业。绿色金融的出现是为了应对气候变化、资源短缺、污染问题等现实挑战,促进经济的绿色转型和可…...

Spring MVC中通过配置文件配置定时任务

Spring MVC中配置定时任务&#xff08;配置文件方式&#xff09; 1.步骤 1.步骤 1-1 在springmvc.xml&#xff08;配置文件&#xff09;的beans中添加 xmlns:task"http://www.springframework.org/schema/task" http://www.springframework.org/schema/task http…...

AI项目十六:YOLOP 训练+测试+模型评估

若该文为原创文章&#xff0c;转载请注明原文出处。 通过正点原子的ATK-3568了解到了YOLOP&#xff0c;这里记录下训练及测试及在onnxruntime部署的过程。 步骤&#xff1a;训练->测试->转成onnx->onnxruntime部署测试 一、前言 YOLOP是华中科技大学研究团队在2021年…...

Flink报错could not be loaded due to a linkage failure

文章目录 1、报错2、原因3、解决 1、报错 在Flink上提交作业&#xff0c;点Submit没反应&#xff0c;F12看到接口报错信息为&#xff1a; 大概意思是&#xff0c;由于链接失败&#xff0c;无法加载程序的入口点类xx。没啥鸟用的信息&#xff0c;去日志目录继续分析&#xff1a…...

网络工程师--网络安全与应用案例分析

前言 需要网络安全学习资料的点击链接&#xff1a;【282G】网络安全&黑客技术零基础到进阶全套学习大礼包&#xff0c;免费分享&#xff01; 案例一&#xff1a; 某单位现有网络拓扑结构如下图所示&#xff0c;实现用户上网功能&#xff0c;该网络使用的网络交换机均为三…...

了解油封对汽车安全的影响?

油封也称为轴封或径向轴封&#xff0c;是车辆发动机、变速箱和其他各种机械系统中的重要部件。它们的主要功能是阻止重要发动机部件的液体(例如油或冷却剂)泄漏&#xff0c;同时防止污染物进入。这些看似简单的任务&#xff0c;但对汽车的安全性和可靠性有着深远的影响。 油封…...

创邻科技Galaxybase—激活数据要素的核心引擎

10月11日下午&#xff0c;创邻科技创始人张晨博士受杭州电子科技大学邀请&#xff0c;前往杭电校园开展交流分享。交流会中&#xff0c;张晨博士为现场的师生带来一场题为《图数据库——激活数据要素的新基建》的精彩分享&#xff0c;探讨数字经济时代底层技术的创新价值与图技…...

【Rust笔记】浅聊 Rust 程序内存布局

浅聊Rust程序内存布局 内存布局看似是底层和距离应用程序开发比较遥远的概念集合&#xff0c;但其对前端应用的功能实现颇具现实意义。从WASM业务模块至Nodejs N-API插件&#xff0c;无处不涉及到FFI跨语言互操作。甚至&#xff0c;做个文本数据的字符集转换也得FFI调用操作系统…...

玻璃生产过程中的窑内压力高精度恒定控制解决方案

摘要&#xff1a;在玻璃生产中对玻璃窑炉中窑压的要求极高&#xff0c;通常需要控制微正压4.7Pa&#xff08;表压&#xff09;&#xff0c;偏差控制在0.3Pa&#xff0c;而窑炉压力还会受到众多因素的影响&#xff0c;所以实现高稳定性的熔窑压力控制具有很大难度&#xff0c;为…...

创意营销:初期推广的多种策略!

文章目录 &#x1f34a; 预热&#x1f389; 制定预热计划和目标&#x1f389; 利用社交媒体传播&#x1f389; 创造独特的体验&#x1f389; 利用口碑营销&#x1f389; 定期发布更新信息&#x1f389; 案例说明 &#x1f34a; 小范围推广&#x1f389; 明确目标用户群体&#…...

【小黑嵌入式系统第一课】嵌入式系统的概述(一)

文章目录 一、嵌入式系统基本概念计算机发展的三大阶段CPU——计算机的核心什么是嵌入式系统嵌入式系统的分类 二、嵌入式系统的特点三、嵌入式系统发展无操作系统阶段简单操作系统阶段实时操作系统阶段面向Internet阶段 四、嵌入式系统的应用工业控制 工业设备通信设备信息家电…...

RK平台使用MP4视频做开机动画以及卡顿问题

rk平台android11以后系统都可以使用MP4格式的视频做开机动画,系统源码里面默认使用的是ts格式的视频,其实使用mp4的视频也是可以的。具体修改如下: diff --git a/frameworks/base/cmds/bootanimation/BootAnimation.cpp b/frameworks/base/cmds/bootanimation/BootAnimat…...

通讯网关软件023——利用CommGate X2HTTP实现HTTP访问Modbus TCP

本文介绍利用CommGate X2HTTP实现HTTP访问Modbus TCP。CommGate X2HTTP是宁波科安网信开发的网关软件&#xff0c;软件可以登录到网信智汇(http://wangxinzhihui.com)下载。 【案例】如下图所示&#xff0c;SCADA系统上位机、PLC、设备具备Modbus RTU通讯接口&#xff0c;现在…...

Python性能测试框架Locust实战教程!

01、认识Locust Locust是一个比较容易上手的分布式用户负载测试工具。它旨在对网站&#xff08;或其他系统&#xff09;进行负载测试&#xff0c;并确定系统可以处理多少个并发用户&#xff0c;Locust 在英文中是 蝗虫 的意思&#xff1a;作者的想法是在测试期间&#xff0c;放…...

c++视觉处理---仿射变换和二维旋转变换矩阵的函数

仿射变换cv::warpAffine cv::warpAffine 是OpenCV中用于执行仿射变换的函数。仿射变换是一种线性变换&#xff0c;可用于执行平移、旋转、缩放和剪切等操作。下面是 cv::warpAffine 函数的基本用法&#xff1a; cv::warpAffine(src, dst, M, dsize, flags, borderMode, borde…...

uiautomator2遍历子元素.all()

当你获取了页面某个元素之后 elements d(’//*[clickable“true”]’).all() 返回的是一个list&#xff0c;其中是<uiautomator2.xpath.XMLElement>类型的变量。 可以通过以下方式获取它所有子类的信息。 for ele in elements:children ele.elem.getchildren()注意…...

【手写数据库toadb】SQL字符串如何被数据库认识? 词法语法分析基础原理,常用工具

词法语法分析 ​专栏内容: 手写数据库toadb 本专栏主要介绍如何从零开发,开发的步骤,以及开发过程中的涉及的原理,遇到的问题等,让大家能跟上并且可以一起开发,让每个需要的人成为参与者。 本专栏会定期更新,对应的代码也会定期更新,每个阶段的代码会打上tag,方便阶段…...

手把手教你基于windows系统使用GNVM进行node切换版本

GNVM是什么&#xff1f; GNVM 是一个简单的 Windows 下 Node.js 多版本管理器&#xff0c;类似的 nvm nvmw nodist 。 安装 进入官网&#xff0c;下载你所需要的包&#xff0c;直达链接 下载完成 放到我们的node环境包下&#xff0c;点击运行 请注意区分: 不存在 Node.js 环…...

c#画五角星

c#画一个五角星,最重要的就是计算哪些坐标点出来,也是最难的一部分,这要涉及到一些数学方面的知识.对数学坐标知识不是很熟的人,如果想学画图,我建议多去看一下数学书,对我们写程序的人来说是没有什么坏处可言的. 想学习的朋友可以一起学习,我觉得分享学习是一种快乐,所以把自…...

第三章 数据链路层 | 计算机网络(谢希仁 第八版)

文章目录 第三章 数据链路层3.1 使用点对点信道的数据链路层3.1.1 数据链路和帧3.1.2 三个基本问题 3.2 点对点协议PPP3.2.1 PPP协议的特点3.2.2 PPP协议的帧格式3.2.3 PPP协议的工作状态 3.3 使用广播信道的数据链路层3.3.1 局域网的数据链路层3.3.2 CSMA/CD协议3.3.3 使用集线…...

李沐机器学习环境配置相关

李沐机器学习环境配置相关 condapython环境安装指令安装miniconda安装cpu版本torch安装jupyter测试GPU是否可以使用 conda 退出 conda 环境 conda deactivate进入都d2l环境 conda activate d2l启动jupyter notebook: jupyter notebookpython 列出所有安装的包 pip lsit环…...

零基础Linux_16(基础IO_文件)笔试选择题:文件描述符+ionde和动静态库

目录 一. 文件描述符等 1. Linux下两个进程可以同时打开同一个文件&#xff0c;这时如下描述错误的是&#xff1a; 2. 以下关于标准输入输出错误的描述正确的是 3. 以下描述正确的是 4. 以下描述正确的是 [多选] 5. 在bash中&#xff0c;在一条命令后加入”1>&2”…...

基于OpenCV的灰度图的图片相似度计算

from skimage.metrics import structural_similarity as ssim import matplotlib.pyplot as plt import cv2 def picture_recognization(imagname):# 读取两张图片image1 cv2.imread(D:/AutoTest/PythonProject/standard_img/ imagname)image2 cv2.imread(D:/AutoTest/Pytho…...

【python海洋专题二十】subplots_adjust布局调整

上期读取soda&#xff0c;并subplot 但是存在一些不完美&#xff0c;本期修饰 本期内容 subplots_adjust布局调整 1&#xff1a;未调整布局的 2&#xff1a;调整布局 往期推荐 【python海洋专题一】查看数据nc文件的属性并输出属性到txt文件 【python海洋专题二】读取水深…...

TensorFlow入门(二十四、初始化学习参数)

参数的初始化关系到网络能否训练出好的结果或者是以多快的速度收敛,对训练结果有着重要的影响。 初始化学习参数需要注意的规则 不可以将网络中的所有参数初始化为0,也不能全部初始化为同一个值。如果参数全部初始化为0或者是同一个值,会使得所有神经元的输出都是相同的,进而造…...

工厂WMS系统货架位管理:优化仓储效率

货架位管理作为WMS系统中的重要环节&#xff0c;对于提高工厂的仓储效率和精确库存管理至关重要。本文将从多个角度全方位介绍工厂的WMS系统货架位管理&#xff0c;探讨其重要性以及如何优化、应用该系统&#xff0c;提升工厂的仓储效率和运营水平。 1. 优化仓库空间利用&…...

[C++随想录] 继承

继承 继承的引言基类和子类的赋值转换继承中的作用域派生类中的默认成员函数继承与友元继承与静态成员多继承的结构棱形继承的结构棱形虚拟继承的结构继承与组合 继承的引言 概念 继承(inheritance)机制是面向对象程序设计使代码可以 复用的最重要的手段&#xff0c;它允许程序…...

ARM-day9

按键控制小灯、蜂鸣器、风扇&#xff0c;按一次启动&#xff0c;第二次关闭 key_it.c #include "key_it.h"//按键3的配置 void key3_it_config() {//RCC使能GPIOF时钟RCC->MP_AHB4ENSETR | (0x1<<5);GPIOF->MODER & (~(0x3<<16));EXTI->E…...

2386: [余姚2015] 幸运数字(luck)

目录 题目描述 输入 输出 样例输入 样例输出 提示 来源: 代码&#xff1a; 题目描述 今年圣诞节&#xff0c;小明收到了很多礼物&#xff0c;每个礼物上都有一个数字&#xff0c;表示对小明的祝福。可是小明有自己的想法&#xff0c;对小明来说&#xff0c;4或者7的倍数…...

【JUC系列-13】深入理解DelayQueue延迟队列的底层原理

JUC系列整体栏目 内容链接地址【一】深入理解JMM内存模型的底层实现原理https://zhenghuisheng.blog.csdn.net/article/details/132400429【二】深入理解CAS底层原理和基本使用https://blog.csdn.net/zhenghuishengq/article/details/132478786【三】熟练掌握Atomic原子系列基本…...

Leetcode---365周赛

题目列表 2873. 有序三元组中的最大值 I 2874. 有序三元组中的最大值 II 2875. 无限数组的最短子数组 2876. 有向图访问计数 一、有序三元组中的最大值I 看一眼该题的数据范围&#xff0c;直接三层for循环暴力枚举&#xff0c;时间复杂度O(n^3)&#xff0c;代码如下 class…...

Java使用opencv实现人脸识别、人脸比对

1. opencv概述 OpenCV是一个开源的计算机视觉库&#xff0c;它提供了一系列丰富的图像处理和计算机视觉算法&#xff0c;包括图像读取、显示、滤波、特征检测、目标跟踪等功能。 opencv官网&#xff1a;https://opencv.org/ opencv官网文档&#xff1a;https://docs.opencv.or…...

Redis HyperLogLog的使用

Redis HyperLogLog知识总结 一、简介二、使用 一、简介 Redis HyperLogLog是一种数据结构&#xff0c;用于高效地计算基数&#xff08;集合中唯一元素的数量&#xff09;。它的主要作用是用于在内存中高效地存储和计算大量数据的基数&#xff0c;而无需完全存储所有的数据。Hy…...

Apisix-Ingress服务发现详解

apisix Apache APISIX 是一个基于微服务 API 网关&#xff0c;其不仅可以处理南北向的流量&#xff0c;也可以处理东西向的流量即服务之间的流量。Apache APISIX 集成了控制面板和数据面&#xff0c;与其他 API 网关相比&#xff0c;Apache APISIX 的上游、路由、插件全是动态的…...

spring6-事务

文章目录 1、JdbcTemplate1.1、简介1.2、准备工作1.3、实现CURD①装配 JdbcTemplate②测试增删改功能③查询数据返回对象④查询数据返回list集合⑤查询返回单个的值 2、声明式事务概念2.1、事务基本概念①什么是事务②事务的特性 2.2、编程式事务2.3、声明式事务 3、基于注解的…...

JavaFx学习问题2--音频、视频播放失败情况

文章目录 一、路径注意事项&#xff1a;① 用相对路径的时候别忘了前面的斜杠② uri问题 二、播放不了的问题① 获取的媒体文件路径本身就是不对的② 必须是uri③ 特殊情况 额外收获: 一、路径注意事项&#xff1a; 完整代码如下: import javafx.application.Application; im…...

第55节—— redux-toolkit中的createReducer——了解

一、概念 当我们使用 Redux 开发应用程序时&#xff0c;一个非常重要的概念就是 reducer。一个 reducer 是一个纯函数&#xff0c;它接受先前的状态和一个动作&#xff0c;然后返回一个新状态。每个动作都会引起状态的变化&#xff0c;从而使应用程序状态管理更加清晰和可控。…...

JUC并发编程——JUC并发编程概述及Lock锁(重点)(基于狂神说的学习笔记)

基于bilibili狂神说JUC并发编程视频所做笔记 概述 什么是JUC JUC时java.util工具包中的三个包的简称 java.util.concurrent java.util.concurrent.atomic java.util.concurrent.locks 业务&#xff1a;普通的线程代码中&#xff0c;我们常使用Runnable接口 但Runnable没有返…...

深入了解 Java 中的时间信息定义、转换、比较和操作

1. 简介 在过去的传统Java日期处理中&#xff0c;经常面临着一些问题。比如&#xff0c;java.util.Date和java.util.Calendar在表示日期和时间时存在着一些奇怪的行为&#xff0c;如月份从0开始计数、对日期进行格式化的方式繁琐不直观等。这些问题给开发带来了一定的困扰。 …...

2023年中国智能矿山发展历程及趋势分析:智能矿山健康有序发展[图]

智能矿山系统对矿山生产提质增效的效果已经开始显现&#xff1a;对不合规、有风险的行动进行及时预警&#xff0c;减少安全事故发生概率&#xff0c;避免因停产整顿产生的巨额亏损&#xff1b;精细化管理整个生产流程&#xff0c;避免过往传统粗放的流程导致的浪费&#xff0c;…...

acwing算法基础之基础算法--整数离散化算法

目录 1 知识点2 模板 1 知识点 整个范围很大&#xff0c;但存在的数据点很少。比如从 − 1 0 9 -10^9 −109到 1 0 9 10^9 109&#xff0c;但总共只有 1 0 6 10^6 106个数。 可以采用离散化的思想来做&#xff0c;即将离散的大数值映射成连续的小数值&#xff08;一般是 1 , …...

基于SSM框架的安全教育平台

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…...