C++ 设计模式 —— 组合模式
C++ 设计模式 —— 组合模式
0. 引用连接
本文主要的思路和代码,来自于对以下连接的学习和实现:
组合模式
1. 引言
1.1 什么是组合模式?
- 组合模式的定义
- 组合模式的作用
组合模式是一种行为型设计模式,它将对象组合成树形结构以表示部分 - 整体的层次结构。这种模式使得用户对单个对象和组合对象的使用具有一致性。组合模式主要应用于需要表示复杂对象结构或者需要将对象组合成树形结构的场景。
组合模式的定义和作用:
定义:组合模式通过一种巧妙的设计方案,可以一致性地处理整个树形结构或者树形结构的一部分,也可以一致性地处理树形结构中的叶子节点(不包含子节点的节点)和容器节点。
作用:组合模式主要解决了在对象组合树中,如何实现一致性的操作和处理的问题。它使得用户可以方便地对对象树进行操作,而不需要考虑对象的具体类型。组合模式还提供了一种灵活的方式来表示对象结构,可以方便地添加和删除对象。
1.2 组合模式与其他设计模式的关系
组合模式是行为型设计模式的一种,它将对象组合成树形结构以表示部分 - 整体的层次结构。在实际应用中,组合模式与其他设计模式有着紧密的联系,常常共同出现在同一个解决方案中。以下是组合模式与其他设计模式的一些关系:
- 装饰者模式 : 装饰者模式与组合模式在结构上有相似之处,但它们的目的不同。装饰者模式通过动态地给一个对象添加职责,使其具有更多的功能,而组合模式关注的是将对象组合成树形结构以表示部分 - 整体的层次结构。两者都依赖于递归组合来组织大量对象。在某些情况下,装饰者模式和组合模式可以结合使用,以实现更加灵活的对象结构。
- 责任链模式 : 责任链模式用于处理具有多个处理步骤的问题,它将请求沿着处理器链进行传递。组合模式则关注将对象组合成树形结构以表示部分 - 整体的层次结构。虽然这两个模式的用途不同,但它们可以结合使用。例如,可以使用组合模式构建一个复杂的对象结构,然后使用责任链模式处理该结构中的请求。
- 迭代器模式 : 迭代器模式允许在不暴露底层数据结构的情况下遍历和访问数据。在组合模式中,可以使用迭代器来遍历复合对象的子元素。迭代器模式抽象了遍历组件的过程,确保每个元素都被访问到,同时不暴露底层数据结构的细节。
- 访问者模式 : 访问者模式允许在不改变对象结构的前提下定义新的操作。在组合模式中,可以将访问者模式应用于复合结构,以便在不更改现有类层次结构的情况下对元素执行操作。访问者模式使您可以在现有代码中添加新行为,而无需修改现有代码。
总之,在实际软件开发中,设计模式往往不会孤立存在。组合模式与其他设计模式之间的紧密联系使得开发人员可以根据具体需求和场景,将这些模式结合使用,以实现更加灵活、高效和可扩展的软件系统。
1.3 组合模式适用的场景
组合模式是一种行为型设计模式,适用于多种场景,如树形对象结构、统一对象处理、动态责任、可变责任和 UI 工具包等。在实际应用中,组合模式与其他设计模式密切相关,共同解决各种问题。以下是组合模式与其他设计模式的一些关系:
- 树形对象结构 : 组合模式适用于实现树形对象结构,如组织结构、文件系统、UI 元素等。这种结构可以方便地表示部分 - 整体的层次关系。在组合模式中,对象通过递归组合形成树状结构,使得客户代码可以统一处理简单元素和复杂元素。
- 统一对象处理 : 组合模式允许客户代码以统一的方式处理简单元素和复杂元素。这种统一处理方式可以简化客户端代码,提高代码的可维护性和可扩展性。通过组合模式,客户端可以忽略对象的复杂内部结构,而仅关注对象的整体行为。
- 动态责任 : 组合模式允许在运行时动态地为单个对象添加责任,而无需修改现有代码。这种动态责任分配可以提高系统的灵活性,使其能够适应不断变化的需求。在组合模式中,可以通过将新的责任分配给现有的对象来实现动态责任。
- 可变责任 : 组合模式适用于责任可能随时间变化的场景。在组合模式中,对象可以具有不同的责任,这使得系统能够适应不断变化的需求。通过组合模式,可以轻松地为对象添加新的责任,而无需修改现有代码。
- UI 工具包 : 组合模式在 UI 工具包中具有广泛的应用。在这种场景下,顶级 UI 元素由许多较小的独立底层 UI 元素组成,这些元素都响应相同的事件和操作。通过使用组合模式,可以轻松地管理 UI 元素的层次结构,并确保它们以一致的方式响应事件。
- 计费系统 : 在计费系统中,组合模式可以应用于处理复杂的活动记录。在这种场景下,重要的是能够生成正确的计费,而不关心活动的具体细节。通过使用组合模式,可以将复杂的活动记录组织成一个树形结构,以便生成正确的计费。
组合模式与其他设计模式密切相关,它们共同解决各种实际问题。在实际应用中,可以根据具体需求和场景,将组合模式与其他设计模式结合使用,以实现更加灵活、高效和可扩展的软件系统。
2. 组合模式的实现
2.1 组合模式概念伪代码
2.1.1 图形概念组合伪代码
CompoundGraphic
类是一个容器,可以包含任意数量的子形状,包括其他复合形状。复合形状具有与简单形状相同的方法。但是,与简单形状不同,复合形状会将请求递归地传递给所有子项,并将结果“求和”。
客户端代码通过与所有形状共享的单一接口与所有形状进行交互。因此,客户端不知道自己正在处理简单形状还是复合形状。客户端可以在不与组成该结构的具体类耦合的情况下处理非常复杂的对象结构。
代码结构分析:
- 定义复合图形类,包含初始化方法和递归调用方法。
- 定义简单图形类,包含初始化方法和基本操作方法。
- 定义客户端代码,通过与所有形状共享的单一接口与所有形状进行交互。
- 在客户端代码中,根据需要创建复合图形对象和简单图形对象。
- 使用复合图形对象和简单图形对象执行各种操作,如添加、删除、修改等。
- 验证客户端代码是否正确处理了复合图形对象和简单图形对象的操作。
// 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
实现的,它声明了公共操作。两个具体类Leaf
和Composite
继承自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
是一个抽象基类,具有三个方法:Add
、Remove
和Delete
。Leaf
和Composite
类继承自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_child
和remove_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()
。这个函数在子类中被重写,用于执行具体的操作。
接下来定义了两个子类:Leaf
和Composite
。Leaf
类表示叶子节点,它从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
,其中包含三个方法:Add
、Remove
和Delete
。Leaf
和Composite
类继承自Component
并实现了这些方法。Composite
类还包含一个Component
指针的向量,表示其子组件。这种结构允许您统一处理单个对象(Leaf
)和对象的组合(Composite
)。
需要注意的是,这段代码是Composite Pattern的基本实现,并没有包含任何特定的功能。需要用自己逻辑替换占位符方法。同时,请记住在使用C++中的原始指针时正确管理内存。如果适用,可以考虑使用智能指针。
我们可以在任何支持C++11或更高版本的C++环境中编译和运行此代码。如果需要想查看这些方法的输出,需要创建Leaf
和Composite
的实例,调用它们的方法,并将输出打印到控制台。
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
中,这些类被实现:
Dot
和Circle
类有构造函数来初始化它们的特性,它们实现了在Graphic
接口中声明的move(int x, int y)
和draw()
方法。CompoundGraphic
类实现了添加或删除子组件、移动所有子组件和绘制所有子组件的方法。ImageEditor
类将组件加载到复合对象中,将选定的组件组合成一个新的复合对象,从旧的复合对象中删除它们,将新的复合对象添加到旧的复合对象中,并绘制所有组件。
这段代码演示了如何使用组合模式统一处理单个对象(Dot
和Circle
)和对象的组成(CompoundGraphic
)。
个人格言
追寻与内心共鸣的生活,未来会逐渐揭晓答案。
Pursue the life that resonates with your heart, and the future will gradually reveal the answer.
相关文章:

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

华为云Stack的学习(九)
十、华为云Stack灾备服务介绍 1.云硬盘备份VBS 云硬盘备份服务(VBS,Volume Backup Service)可为云硬盘(EVS,Elastic Volume Service)创建备份,利用备份数据恢复云硬盘,最大限度保障…...
Flink中jobmanager、taskmanager、slot、task、subtask、Parallelism的概念
场景 一个工厂有三个车间每个车间两条生产线 生产流程如下 原料->加工->过滤->分类->美化->包装->下线 JobManager:工厂 在上述场景中,工厂就是jobManager,负责协调、调度和监控整个生产过程 TaskManager:车间…...

OpenHarmony docker环境搭建
OpenHarmony docker环境搭建 要求一台安装ubuntu的虚拟机,vscode软件 安装docker 在 Ubuntu 上安装 Docker 非常直接。我们将会启用 Docker 软件源,导入 GPG key,并且安装软件包。 首先,更新软件包索引,并且安装必要的依赖软件…...
【计算机网络】网络编程接口 Socket API 解读(11)
Socket 是网络协议栈暴露给编程人员的 API,相比复杂的计算机网络协议,API 对关键操作和配置数据进行了抽象,简化了程序编程。 本文讲述的 socket 内容源自 Linux man。本文主要对各 API 进行详细介绍,从而更好的理解 socket 编程。…...

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

【深度学习】DDPM,Diffusion,概率扩散去噪生成模型,原理解读
看过来看过去,唯有此up主,非常牛: Video Explaination(Chinese) 1. DDPM Introduction q q q - 一个固定(或预定义)的正向扩散过程,逐渐向图像添加高斯噪声,直到最终得到纯噪声。 p θ p_θ p…...

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

利达卓越:关注环保事业,持续赋能科技
随着全球环境问题的日益突出,绿色金融作为一种新兴的金融模式逐渐受到各国的重视。绿色金融是指在金融活动中,通过资金、信贷和风险管理等手段,支持环境友好和可持续发展的项目和产业。绿色金融的出现是为了应对气候变化、资源短缺、污染问题等现实挑战,促进经济的绿色转型和可…...
Spring MVC中通过配置文件配置定时任务
Spring MVC中配置定时任务(配置文件方式) 1.步骤 1.步骤 1-1 在springmvc.xml(配置文件)的beans中添加 xmlns:task"http://www.springframework.org/schema/task" http://www.springframework.org/schema/task http…...

AI项目十六:YOLOP 训练+测试+模型评估
若该文为原创文章,转载请注明原文出处。 通过正点原子的ATK-3568了解到了YOLOP,这里记录下训练及测试及在onnxruntime部署的过程。 步骤:训练->测试->转成onnx->onnxruntime部署测试 一、前言 YOLOP是华中科技大学研究团队在2021年…...

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

网络工程师--网络安全与应用案例分析
前言 需要网络安全学习资料的点击链接:【282G】网络安全&黑客技术零基础到进阶全套学习大礼包,免费分享! 案例一: 某单位现有网络拓扑结构如下图所示,实现用户上网功能,该网络使用的网络交换机均为三…...
了解油封对汽车安全的影响?
油封也称为轴封或径向轴封,是车辆发动机、变速箱和其他各种机械系统中的重要部件。它们的主要功能是阻止重要发动机部件的液体(例如油或冷却剂)泄漏,同时防止污染物进入。这些看似简单的任务,但对汽车的安全性和可靠性有着深远的影响。 油封…...

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

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

玻璃生产过程中的窑内压力高精度恒定控制解决方案
摘要:在玻璃生产中对玻璃窑炉中窑压的要求极高,通常需要控制微正压4.7Pa(表压),偏差控制在0.3Pa,而窑炉压力还会受到众多因素的影响,所以实现高稳定性的熔窑压力控制具有很大难度,为…...

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

【小黑嵌入式系统第一课】嵌入式系统的概述(一)
文章目录 一、嵌入式系统基本概念计算机发展的三大阶段CPU——计算机的核心什么是嵌入式系统嵌入式系统的分类 二、嵌入式系统的特点三、嵌入式系统发展无操作系统阶段简单操作系统阶段实时操作系统阶段面向Internet阶段 四、嵌入式系统的应用工业控制 工业设备通信设备信息家电…...
RK平台使用MP4视频做开机动画以及卡顿问题
rk平台android11以后系统都可以使用MP4格式的视频做开机动画,系统源码里面默认使用的是ts格式的视频,其实使用mp4的视频也是可以的。具体修改如下: diff --git a/frameworks/base/cmds/bootanimation/BootAnimation.cpp b/frameworks/base/cmds/bootanimation/BootAnimat…...

网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...

Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...

Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...