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

news2024/11/26 2:42:23

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 is
    method 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 is
    field x, y

    constructor Dot(x, y) { ... }

    method move(x, y) is
        this.x += x, this.y += y

    method draw() is
        // Draw a dot at X and Y.

// All component classes can extend other components.
class Circle extends Dot is
    field radius

    constructor 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 is
    field 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) is
        foreach (child in children) do
            child.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 is
    field all: CompoundGraphic

    method load() is
        all = 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) is
        group = new CompoundGraphic()
        foreach (component in components) do
            group.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):
        pass

    def remove_file(self, file):
        pass

    def list_files(self):
        pass

# 具体部分
class File:
    def __init__(self, name):
        self.name = name

class DirectoryNode:
    def __init__(self, directory):
        self.directory = directory
        self.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.

在这里插入图片描述

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

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

相关文章

解决react使用css module无法重写bootstrap样式的问题

react使用css module虽然能够解决样式污染&#xff0c;但是同时也失去了写css样式的灵活性&#xff0c;特别是&#xff1a;在.module.css文件中当子元素是非变量的静态class类&#xff08;比如bootstrap&#xff09;, 此时使用css选择器对该子元素的样式不会起作用的 比如下面…

【干货】VS2017简介、编译、启动单项目和启动多项目

1. VS2017简单介绍 解决方案和项目的区别&#xff1a; 一般一个解决方案会有多个项目&#xff0c;一个项目里面一般只有一个main文件&#xff0c;所以需要右键单击某个项目将其设置成启动项目&#xff0c;才可以启动该项目。 2. 编译github的代码仓 一般都会有CMakeLists.t…

《C++ Primer》练习9.43-练习9.46:替换字符串简写和插入前后缀

文章目录 练习9.43练习9.44练习9.45练习9.46总结参考 练习9.43 练习9.43要替换字符串s中所有oldVal为newVal&#xff0c;要求使用迭代器和insert以及erase函数。 #include <iostream> #include <string> #include <vector> using namespace std;string &a…

ubuntu下yolov5 tensorrt模型部署

文章目录 ubuntu下yolov5 tensorrt模型部署一、Ubuntu18.04环境配置1.1 安装工具链和opencv1.2 安装Nvidia相关库1.2.1 安装Nvidia显卡驱动1.2.2 安装 cuda11.31.2.3 安装 cudnn8.21.2.4 下载 tensorrt8.4.2.41.2.5 下载仓库TensorRT-Alpha并设置 二、从yolov5源码中导出onnx文…

【IDEA项目个别类爆红,但是项目可以正常运行】

打开项目时发现idea个别类爆红,但是项目可以正常运行 问题原因&#xff1a;Idea本身的问题&#xff0c;可能是其缓存问题&#xff0c;导致爆红 解决方案&#xff1a;重置Idea 很多时候排查不出代码问题&#xff0c;就尝试一下此操作。 选择目录&#xff1a;File–>Invalida…

前后端分离项目-基于springboot+vue的高校学科竞赛平台的设计与实现(内含代码+文档+报告)

博主介绍&#xff1a;✌全网粉丝10W,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业毕业设计项目实战6年之久&#xff0c;选择我们就是选择放心、选择安心毕业✌ &#x1f345;由于篇幅限制&#xff0c;想要获取完整文章或者源码&#xff0c;或者代做&am…

node.js+NPM包管理器+Webpack打包工具+前端项目搭建

javascript运行环境&#xff08;无需依赖html文件&#xff09; BFF&#xff0c;服务于前端的后端 官网下载安装&#xff0c;node -v查看是否安装成功 ①、创建一个01.js文件 //引入http模块 const httprequire(http)//创建服务器 http.createServer(function(request,respo…

微服务+Java+Spring Cloud +UniApp +MySql智慧工地综合管理云平台源码,SaaS模式

智慧工地围绕工程现场人、机、料、法、环及施工过程中质量、安全、进度、成本等各项数据满足工地多角色、多视角的有效监管,实现工程建设管理的降本增效. 智慧工地综合管理云平台源码&#xff0c;PC监管端、项目端&#xff1b;APP监管端、项目端、数据可视化大屏端源码&#xf…

css案例:取消组件的阴影

点击的时候会出现阴影&#xff0c;取消阴影操作&#xff1a; .el-radio__input.is-checked{.el-radio__inner{box-shadow:0 0 0 0!important;}}有的时候取消阴影的css不起作用是权限问题&#xff0c;加上!important 就好了。

Ps:选区的布尔运算

选区的布尔 Boolean运算指的是选区之间的相加&#xff08;并集&#xff09;、相减&#xff08;差集&#xff09;以及相交&#xff08;交集&#xff09;&#xff0c;从而形成一个新的选区。 ◆ ◆ ◆ 使用工具选项栏 在 Ps 中&#xff0c;几乎所有的选区工具的工具选项栏上都有…

php新手实战:自定义书源下载api

网上有很多第三方小说网站提供小说下载&#xff0c;而下载的过程无非就是搜索书籍&#xff0c;然后找到下载链接点击下载即可。只是类似这种“良心”的小说网站实在是太少。大多数仅支持在线阅读。而如今&#xff0c;我却要利用这种为数不多的“良心”小说站点提供的书源来作为…

Eureka添加@Loadbalanced 报错 No instances available for XXXXX

错误显示为 错误信息是:没有可用的实例 我就比较惊讶 我已经添加了Loadbalanced 同时将RestTemplate注册到spring容器中了 为什么还会出现没有实例.. 下面是代码 仔细检查了代码发现没什么错误之后 检查了一下 xml文件,发现里面的 应用名称与访问时参数一致.这个时候就陷…

Elasticsearch:使用 LangChain 对话链和 OpenAI 的聊天机器人

在此笔记本中&#xff0c;我们将构建一个聊天机器人&#xff0c;它可以回答有关自定义数据的问题&#xff0c;例如雇主的政策。 聊天机器人使用 LangChain 的 ConversationalRetrievalChain&#xff0c;具有以下功能&#xff1a; 用自然语言回答问题在 Elasticsearch 中运行混…

Postman持久化保存/设置断言详解

postman持久化保存 1、点击postman的Collections页签&#xff0c;点击 New Collection创建&#xff08;可以当成项 目并重命名&#xff09; 2、新增后&#xff0c;再点击Collection中的“ ... ” &#xff0c;然后点击“Add Folder”&#xff0c;新建一个文件 夹&#xff08…

是否拥有具身智能,是扫地机器人能否打破“内卷”的关键

如果你关注2023世界人工智能大会等行业峰会&#xff0c;以及英伟达、微软、谷歌、特斯拉和国內科技大厂的最新发布会&#xff0c;除了“大模型”&#xff0c;应该会听到另一个高频词——具身智能。 所谓具身智能Embodied AI &#xff0c;指的是有身体并支持物理交互的智能体。这…

【计网】傻瓜式安装cpolar内网穿透

目录 一、注册账户 二、下载安装包 三、安装 四、查看AuthToken 五、简单使用 如果在本机部署项目外网是访问不到的&#xff0c;通过内网穿透就可以使本机部署的项目可被外网访问 一、注册账户 cpolar - secure introspectable tunnels to localhostcpolar secure intro…

3. Windows下C++/MFC调用hiredis库操作redis示例

一、头文件目录 将之前下载和编译好的Redis目录拷贝到新建好的工程目录下面&#xff0c;再点击测试工程的右键/属性&#xff0c;点击C/常规&#xff0c;附加包含目录添加以下路径&#xff0c;注意如果原先有多个路径&#xff0c;在末尾处添加分号后再粘贴&#xff1a; 点击C/常…

谜题(Puzzle, ACM/ICPC World Finals 1993, UVa227)

有一个5*5的网格&#xff0c;其中恰好有一个格子是空的&#xff0c;其他格子各有一个字母。一共有4种指令&#xff1a;A, B, L, R&#xff0c;分别表示把空格上、下、左、右的相邻字母移到空格中。输入初始网格和指令序列&#xff08;以数字0结束&#xff09;&#xff0c;输出指…

深入promise

深入promise 我们可能知道如何使用 Promise&#xff0c;但是我们知道它们实际上是如何工作的吗&#xff1f; 为了让每个人都了解Promise&#xff0c;让我们从基础开始。如果我们知道 Promise 是什么以及如何使用它&#xff0c;我们可以跳过这一部分并直接跳到“魔法开始”的地…

Halcon中涉及的数字图像十大理论知识

1.图像处理知识 2.图像的灰度变换 3.图像增强 4.图像的几何变换 5.图像分割 6.图像的频域 7.图像的形态学 8.图像的复原 9.运动图像 10.图像配准