结构型设计模式—组合模式

news2024/9/21 2:33:26

结构型设计模式—组合模式

欢迎长按图片加好友,我会第一时间和你分享持续更多的开发知识,面试资源,学习方法等等。

组合模式(Composite Pattern)是一种结构型设计模式,它允许你将对象组合成树形结构来表示“部分-整体”的层次结构。通过这种模式,客户端可以统一地处理单个对象和对象组合。

想象一下,你家里有各种电器,比如电视、空调、冰箱、洗衣机等。这些电器可以分为不同的房间,如客厅、卧室、厨房等。每个房间可能有多个电器,而整个家就是由这些房间和电器组成的。

  • 叶子对象:每个电器(如电视、冰箱)就是一个叶子对象,它们没有子对象。
  • 组合对象:每个房间(如客厅、卧室)就是一个组合对象,它包含了多个电器。
  • 根对象:整个家庭就是一个顶层的组合对象,它包含了多个房间。

通过组合模式,你可以将家庭结构视为一个整体。无论是处理单个电器(叶子对象),还是处理整个家庭(根对象),你都可以使用统一的方式。例如,你可以写一个功能来关闭所有电器,无论是关闭单个电器,还是关闭某个房间里的所有电器,或者关闭整个家里的所有电器,这个功能的实现方式都是一样的。

组合模式概述

对于树形结构,当容器对象(例如文件夹)的某一个方法被调用时,将遍历整个树形结构,寻找也包含这个方法的成员对象(可以是容器对象,也可以是叶子对象)并调用执行,牵一而动百,其中使用了递归调用的机制来对整个结构进行处理。由于容器对象和叶子对象在功能上的区别,在使用这些对象的代码中必须有区别地对待容器对象和叶子对象,而实际上大多数情况下希望一致地处理它们,因为对于这些对象的区别对待将会使得程序非常复杂。组合模式为解决此类问题而诞生,它可以让叶子对象和容器对象的使用具有一致性。

组合模式定义如下:

组合模式(Composite Pattern):**组合多个对象形成树形结构以表示具有“部分—整体”关系的层次结构。**组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,又可以称为“部分—整体”(Part-Whole)模式,它是一种对象结构型模式。

在组合模式中引入了抽象构件类Component,它是所有容器类和叶子类的公共父类,客户端针对Component进行编程。组合模式结构如图所示。

在组合模式结构图中包含以下3个角色:

  1. Component(抽象构件):它可以是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法,例如增加子构件、删除子构件、获取子构件等。
  2. Leaf(叶子构件):它在组合模式结构中表示叶子节点对象。叶子节点没有子节点,它实现了在抽象构件中定义的行为。对于那些访问及管理子构件的方法,可以通过捕获异常等方式进行处理。
  3. Composite(容器构件):它在组合模式结构中表示容器节点对象。容器节点包含子节点,其子节点可以是叶子节点,也可以是容器节点。它提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法,在其业务方法中可以递归调用其子节点的业务方法。

组合模式的关键是定义了一个抽象构件类,它既可以代表叶子,又可以代表容器。客户端针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。同时容器对象与抽象构件类之间还建立一个聚合关联关系,在容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合,形成一个树形结构。

如果不使用组合模式,客户端代码将过多地依赖于容器对象复杂的内部实现结构。容器对象内部实现结构的变化将引起客户代码的频繁变化,从而带来了代码维护复杂、可扩展性差等弊端。组合模式的引入将在一定程度上解决这些问题。

下面通过简单的示例代码来分析组合模式中各个角色的用途和实现。

  1. Component(组件):定义了组合对象和叶子对象的共同接口或抽象类。所有对象(包括组合对象和叶子对象)都需要实现该接口或继承该抽象类。
  2. Leaf(叶子节点):叶子节点是组合中的基本元素,没有子节点。在你的案例中,具体的电器(如 TV 和 AirConditioner)就是叶子节点。
  3. Composite(组合节点):组合节点包含子节点,可以是叶子节点或其他组合节点。它实现了 Component 的接口,并且可以包含其他组件(包括叶子和组合)。在你的案例中,房间(Room)和房子(House)就是组合节点。
// 1. Component(组件):定义了组合和叶子节点的共同接口或抽象类
abstract class Appliance {
    public abstract void turnOff();
}

// 2. Leaf(叶子节点):表示具体的电器,如 TV 和 AirConditioner,没有子节点
class TV extends Appliance {
    @Override
    public void turnOff() {
        System.out.println("Turning off the TV");
    }
}

class AirConditioner extends Appliance {
    @Override
    public void turnOff() {
        System.out.println("Turning off the Air Conditioner");
    }
}

// 3. Composite(组合节点):包含子节点的组合对象,既可以包含叶子节点,也可以包含其他组合节点
class Room extends Appliance {
    private List<Appliance> appliances = new ArrayList<>();

    public void addAppliance(Appliance appliance) {
        appliances.add(appliance);
    }

    @Override
    public void turnOff() {
        for (Appliance appliance : appliances) {
            appliance.turnOff();
        }
    }
}

// 另一个 Composite(组合节点):表示整个家,可以包含多个房间(Room)
class House extends Appliance {
    private List<Appliance> rooms = new ArrayList<>();

    public void addRoom(Room room) {
        rooms.add(room);
    }

    @Override
    public void turnOff() {
        for (Appliance room : rooms) {
            room.turnOff();
        }
    }
}

// 4. 客户端代码
public class CompositePatternDemo {
    public static void main(String[] args) {
        // 创建房间及其电器
        Room livingRoom = new Room();
        livingRoom.addAppliance(new TV());
        livingRoom.addAppliance(new AirConditioner());

        Room bedroom = new Room();
        bedroom.addAppliance(new TV());

        // 创建家并添加房间
        House house = new House();
        house.addRoom(livingRoom);
        house.addRoom(bedroom);

        // 关闭整个家中的所有电器
        house.turnOff();
    }
}
  1. Component(组件):Appliance 抽象类是 Component 角色,它定义了 turnOff() 方法,这是叶子节点和组合节点的共同接口。
  2. Leaf(叶子节点):TV 和 AirConditioner 类是 Leaf 角色,它们实现了 Appliance 的 turnOff() 方法,并且没有子节点。
  3. Composite(组合节点):Room 和 House 类是 Composite 角色,它们实现了 Appliance 的 turnOff() 方法,并包含了其他 Appliance 对象作为子节点。它们可以包含 Leaf 角色或其他 Composite 角色。

通过这个代码示例,你可以清楚地看到组合模式中的三个角色是如何协同工作的。客户端可以通过 Component 接口统一操作单个对象(叶子节点)或组合对象(组合节点)。

透明组合模式和安全组合模式

透明组合模式和安全组合模式的存在,是因为开发者在设计软件时需要在灵活性安全性之间做出权衡。这两种变体的出现,反映了不同的设计需求和设计哲学。透明组合模式安全组合模式是组合模式的两种变体,它们处理组件的方式略有不同,主要区别在于如何管理组合对象和叶子对象。

透明组合模式(Transparent Composite Pattern)

透明组合模式的设计初衷是为了简化客户端的使用,让客户端不必区分是操作叶子节点还是组合节点,统一使用同一套接口进行操作。

  • 透明性:在透明组合模式中,叶子节点和组合节点都实现了相同的接口,包括对组合节点有意义的操作(如 add()remove())。这样,客户端代码可以对组件进行统一的操作,而不需要区分当前操作的对象是叶子节点还是组合节点。
  • 简化客户端代码:由于客户端可以忽略对象的类型(叶子节点还是组合节点),可以更加方便地操作对象树结构。比如,客户端可以遍历整个树结构,执行 turnOff() 操作而不关心对象是叶子还是组合。
  • 灵活性:透明组合模式非常灵活,能够处理复杂的对象层次结构,特别是在需要频繁操作和修改对象结构的场景中。

但是同时透明组合模式的灵活性是以接口的安全性为代价的。叶子节点实现了组合操作(如 add()remove()),尽管这些操作对它们无意义。这可能导致在客户端误用这些操作,从而产生运行时错误。

下面通过简单的示例代码来分析透明组合模式中各个角色的用途和实现。

在透明组合模式中,Component 接口中包含了组合操作的方法(如 add、remove),叶子节点和组合节点都实现这些方法。

// Component(组件):定义了组合对象和叶子节点的共同接口
abstract class Appliance {
    // 透明组合模式中,add 和 remove 方法在 Component 中定义
    // 叶子节点将实现这些方法,但它们在叶子节点中没有实际意义
    public void add(Appliance appliance) {
        throw new UnsupportedOperationException();
    }

    public void remove(Appliance appliance) {
        throw new UnsupportedOperationException();
    }

    public abstract void turnOff();
}

// Leaf(叶子节点):表示具体的电器,如 TV 和 AirConditioner,没有子节点
class TV extends Appliance {
    @Override
    public void turnOff() {
        System.out.println("Turning off the TV");
    }
}

class AirConditioner extends Appliance {
    @Override
    public void turnOff() {
        System.out.println("Turning off the Air Conditioner");
    }
}

// Composite(组合节点):包含子节点的组合对象,既可以包含叶子节点,也可以包含其他组合节点
class Room extends Appliance {
    private List<Appliance> appliances = new ArrayList<>();

    @Override
    public void add(Appliance appliance) {
        appliances.add(appliance);
    }

    @Override
    public void remove(Appliance appliance) {
        appliances.remove(appliance);
    }

    @Override
    public void turnOff() {
        for (Appliance appliance : appliances) {
            appliance.turnOff();
        }
    }
}

// 另一个 Composite(组合节点):表示整个家,可以包含多个房间(Room)
class House extends Appliance {
    private List<Appliance> rooms = new ArrayList<>();

    @Override
    public void add(Appliance appliance) {
        rooms.add(appliance);
    }

    @Override
    public void remove(Appliance appliance) {
        rooms.remove(appliance);
    }

    @Override
    public void turnOff() {
        for (Appliance room : rooms) {
            room.turnOff();
        }
    }
}

// 客户端代码
public class TransparentCompositePatternDemo {
    public static void main(String[] args) {
        // 创建房间及其电器
        Room livingRoom = new Room();
        livingRoom.add(new TV());
        livingRoom.add(new AirConditioner());

        Room bedroom = new Room();
        bedroom.add(new TV());

        // 创建家并添加房间
        House house = new House();
        house.add(livingRoom);
        house.add(bedroom);

        // 关闭整个家中的所有电器
        house.turnOff();
    }
}
  • Component(组件):Appliance 是抽象类,定义了组合操作方法(addremove),叶子节点虽然实现了这些方法,但在叶子节点中它们抛出了 UnsupportedOperationException
  • Leaf(叶子节点):TV 和 AirConditioner 是叶子节点,虽然它们实现了 addremove 方法,但这些方法在叶子节点中没有实际用途。
  • Composite(组合节点):Room 和 House 是组合节点,包含了 addremove 方法,允许子节点(叶子或组合)被添加或移除,并实现了统一的 turnOff 操作。

安全组合模式

安全组合模式的设计初衷是为了提供更高的安全性和清晰的接口设计。它避免了叶子节点实现不必要的方法,从而减少了误用的风险。

  • 安全性:安全组合模式通过将组合操作(如 add()、remove())限定在组合节点中,从而避免叶子节点中出现这些无意义的操作。这种方式确保了客户端只能在组合节点上调用这些方法,而不会在叶子节点上误调用。
  • 清晰的接口设计:安全组合模式将叶子节点和组合节点的职责分离得更加明确,接口设计更加简洁,减少了误解和误用的可能性。
  • 降低出错风险:因为叶子节点没有实现组合操作,所以客户端无法误用这些方法,降低了程序出错的风险。

但是安全组合模式的严格区分增加了客户端代码的复杂性。客户端需要知道它正在处理的是叶子节点还是组合节点,从而调用不同的方法。这种情况下,客户端代码可能变得更加复杂,需要进行类型检查或使用多态来处理不同的情况。

下面通过简单的示例代码来分析安全组合模式中各个角色的用途和实现。

在安全组合模式中,Component 接口只包含通用操作(如 turnOff),组合操作(如 addremove)仅在组合节点中定义,叶子节点不需要实现这些方法。

// Component(组件):定义了通用操作,不包含组合操作
abstract class Appliance {
    public abstract void turnOff();
}

// Leaf(叶子节点):表示具体的电器,如 TV 和 AirConditioner,没有子节点,也不实现组合操作
class TV extends Appliance {
    @Override
    public void turnOff() {
        System.out.println("Turning off the TV");
    }
}

class AirConditioner extends Appliance {
    @Override
    public void turnOff() {
        System.out.println("Turning off the Air Conditioner");
    }
}

// Composite(组合节点):包含子节点的组合对象,定义组合操作如 add 和 remove
class Room extends Appliance {
    private List<Appliance> appliances = new ArrayList<>();

    // 组合操作在 Composite 中定义,安全组合模式下,叶子节点不需要实现这些方法
    public void add(Appliance appliance) {
        appliances.add(appliance);
    }

    public void remove(Appliance appliance) {
        appliances.remove(appliance);
    }

    @Override
    public void turnOff() {
        for (Appliance appliance : appliances) {
            appliance.turnOff();
        }
    }
}

// 另一个 Composite(组合节点):表示整个家,可以包含多个房间(Room)
class House extends Appliance {
    private List<Appliance> rooms = new ArrayList<>();

    public void add(Room room) {
        rooms.add(room);
    }

    public void remove(Room room) {
        rooms.remove(room);
    }

    @Override
    public void turnOff() {
        for (Appliance room : rooms) {
            room.turnOff();
        }
    }
}

// 客户端代码
public class SafeCompositePatternDemo {
    public static void main(String[] args) {
        // 创建房间及其电器
        Room livingRoom = new Room();
        livingRoom.add(new TV());
        livingRoom.add(new AirConditioner());

        Room bedroom = new Room();
        bedroom.add(new TV());

        // 创建家并添加房间
        House house = new House();
        house.add(livingRoom);
        house.add(bedroom);

        // 关闭整个家中的所有电器
        house.turnOff();
    }
}
  • Component(组件):Appliance 只定义了 turnOff 方法,没有组合操作(addremove),叶子节点和组合节点都继承了这个接口。
  • Leaf(叶子节点):TV 和 AirConditioner 是叶子节点,它们只实现了 turnOff 方法,不需要实现组合操作,因此接口更加简洁明了。
  • Composite(组合节点):Room 和 House 是组合节点,它们定义了组合操作方法(addremove),并通过 turnOff 方法遍历并关闭所有子节点。

透明组合模式与安全组合模式总结

  • 透明组合模式:优先考虑灵活性和统一性,适合处理复杂的对象结构,客户端代码简单,但接口不够安全,可能导致误用。
  • 安全组合模式:优先考虑安全性和接口清晰性,避免叶子节点实现无意义的操作,减少误用风险,但客户端代码可能会更复杂。

这两种模式之间的选择,取决于具体应用场景和开发者的设计需求。如果你的应用需要大量的对象层次结构操作,且不希望让客户端区分叶子和组合对象,透明组合模式可能更合适;如果你需要确保接口的安全性,并减少误用的风险,安全组合模式则可能是更好的选择。

组合模式总结

组合模式使用面向对象的思想来实现树形结构的构建与处理,描述了如何将容器对象和叶子对象进行递归组合,实现简单,灵活性好。由于在软件开发中存在大量的树形结构,因此组合模式是一种使用频率较高的结构型设计模式。

优点

  1. 组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次。它让客户端忽略了层次的差异,方便对整个层次结构进行控制。
  2. 客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码。
  3. 在组合模式中增加新的容器构件和叶子构件都很方便,无须对现有类库进行任何修改,符合开闭原则。
  4. 组合模式为树形结构的面向对象实现提供了一种灵活的解决方案。通过叶子对象和容器对象的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单。

缺点

组合模式的主要缺点是:在增加新构件时很难对容器中的构件类型进行限制。有时希望一个容器中只能有某些特定类型的对象,例如在某个文件夹中只能包含文本文件。使用组合模式时,不能依赖类型系统来施加这些约束,因为它们都来自相同的抽象层。在这种情况下,必须通过在运行时进行类型检查来实现,这个实现过程较为复杂。

适用场景

  1. 在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以一致性地对待它们。
  2. 在一个使用面向对象语言开发的系统中需要处理一个树形结构。
  3. 在一个系统中能够分离出叶子对象和容器对象,而且它们的类型不固定,将来需要增加一些新的类型。

案例

Sunny软件公司欲开发一个界面控件库。界面控件分为两大类:一类是单元控件,例如按钮、文本框等;另一类是容器控件,例如窗体、中间面板等。试用组合模式设计该界面控件库。

我们将控件分为两大类:

  1. 单元控件:如按钮、文本框等,这些控件不能包含其他控件。
  2. 容器控件:如窗体、中间面板等,这些控件可以包含其他控件(包括单元控件和容器控件)。

角色说明

  • Component(组件):定义所有控件的通用接口,既包括单元控件也包括容器控件的通用操作。
  • Leaf(叶子节点):表示单元控件,如按钮、文本框等。这些控件没有子控件。
  • Composite(组合节点):表示容器控件,如窗体、中间面板等,可以包含其他控件(包括叶子节点和组合节点)。

下面是使用 Java 实现的界面控件库的组合模式设计:

import java.util.ArrayList;
import java.util.List;

// Component(组件):定义所有控件的通用接口
abstract class UIComponent {
    public void add(UIComponent component) {
        throw new UnsupportedOperationException();
    }

    public void remove(UIComponent component) {
        throw new UnsupportedOperationException();
    }

    public UIComponent getChild(int index) {
        throw new UnsupportedOperationException();
    }

    public abstract void render(); // 渲染控件
}

// Leaf(叶子节点):表示单元控件,如按钮、文本框等
class Button extends UIComponent {
    @Override
    public void render() {
        System.out.println("Rendering Button");
    }
}

class TextBox extends UIComponent {
    @Override
    public void render() {
        System.out.println("Rendering TextBox");
    }
}

// Composite(组合节点):表示容器控件,如窗体、中间面板等
class Panel extends UIComponent {
    private List<UIComponent> children = new ArrayList<>();

    @Override
    public void add(UIComponent component) {
        children.add(component);
    }

    @Override
    public void remove(UIComponent component) {
        children.remove(component);
    }

    @Override
    public UIComponent getChild(int index) {
        return children.get(index);
    }

    @Override
    public void render() {
        System.out.println("Rendering Panel");
        for (UIComponent component : children) {
            component.render(); // 递归渲染子控件
        }
    }
}

class Window extends UIComponent {
    private List<UIComponent> children = new ArrayList<>();

    @Override
    public void add(UIComponent component) {
        children.add(component);
    }

    @Override
    public void remove(UIComponent component) {
        children.remove(component);
    }

    @Override
    public UIComponent getChild(int index) {
        return children.get(index);
    }

    @Override
    public void render() {
        System.out.println("Rendering Window");
        for (UIComponent component : children) {
            component.render(); // 递归渲染子控件
        }
    }
}

// 客户端代码
public class CompositePatternDemo {
    public static void main(String[] args) {
        // 创建单元控件
        Button button1 = new Button();
        TextBox textBox1 = new TextBox();

        // 创建容器控件并添加单元控件
        Panel panel = new Panel();
        panel.add(button1);
        panel.add(textBox1);

        // 创建窗体并添加面板
        Window window = new Window();
        window.add(panel);

        // 渲染整个界面
        window.render();
    }
}

代码解析

  • Component(组件):UIComponent 是抽象类,定义了所有控件的通用接口,包含了组合操作(addremovegetChild)和渲染操作(render)。
  • Leaf(叶子节点):Button 和 TextBox 是单元控件,只实现了渲染操作(render),不包含组合操作(addremove 等),这些操作在 UIComponent 中抛出了 UnsupportedOperationException
  • Composite(组合节点):Panel 和 Window 是容器控件,它们实现了组合操作(addremovegetChild),并且在 render 方法中递归地渲染它们包含的所有子控件。

优点

一致性:客户端可以统一处理单元控件和容器控件,而不需要区分它们的类型。

灵活性:通过组合模式,可以轻松地构建复杂的控件层次结构。

可扩展性:可以方便地增加新的控件类型(叶子或组合)而不需要修改现有代码。

这个设计使得开发人员能够轻松地扩展控件库,并通过统一的接口来处理各种控件,极大地提高了代码的可维护性和可重用性。

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

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

相关文章

亿图图示下载安装教程EdrawMax Pro 13版超详细图文教程

亿图图示下载安装教程EdrawMax Pro 13版超详细图文教程&#xff1a; 亿图图示是一款功能强大的综合绘图软件&#xff0c;具有以下特点和功能 丰富的绘图类型&#xff1a;涵盖 210 余种办公绘图类型&#xff0c;包括流程图、思维导图、信息图、工业设计、组织架构图、平面设计…

k8s使用报错

报错内容&#xff1a; [rootk8s-master ~]# kubectl get nodes E0903 17:21:22.183325 4630 memcache.go:265] couldnt get current server API group list: Get "https://172.25.250.100:6443/api?timeout32s": dial tcp 172.25.250.100:6443: connect: connec…

多目标应用:基于环形拓扑的多目标粒子群优化算法(MO_Ring_PSO_SCD)的移动机器人路径规划研究(提供MATLAB代码)

一、机器人路径规划介绍 移动机器人&#xff08;Mobile robot&#xff0c;MR&#xff09;的路径规划是 移动机器人研究的重要分支之&#xff0c;是对其进行控制的基础。根据环境信息的已知程度不同&#xff0c;路径规划分为基于环境信息已知的全局路径规划和基于环境信息未知或…

SpringBoot2:配置类的一般写法

1、知识准备 首先&#xff0c;我们要知道&#xff0c;springboot的配置类的构造器&#xff0c;构造器参数&#xff0c;是从IOC容器中获取的。 2、案例说明 我随便找个springboot的一个自动配置类 org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAuto…

阻塞队列-单锁实现

使用阻塞队列 当我们多个线程下 对 一个队列进行操作&#xff0c;队列满了的情况下&#xff0c;其他线程再次 offer&#xff0c;会一直阻塞等待 对一个队列进行出队操作的时候&#xff0c;队列空的情况下&#xff0c;会一直阻塞等待删除&#xff0c;直到队列有元素的时候&a…

Java-线程的生命周期7大状态

在 Java 中&#xff0c;线程的生命周期可以分为多个状态&#xff0c;这些状态描述了线程从创建到终止的整个过程。Java 线程的生命周期主要包括以下七大状态&#xff1a; 1.新建状态&#xff08;New&#xff09; 当一个线程对象被创建但尚未调用 start() 方法时&#xff0c;线…

Zabbix结合Grafana

一、Grafana简介 Grafana 是 Graphite 和 InfluxDB 仪表盘和图形编辑器。Grafana 是开源的&#xff0c;功能齐全的度量仪表盘和图形编辑器&#xff0c;支持 Graphite&#xff0c;InfluxDB 和 OpenTSDB。 Grafana 主要特性&#xff1a;灵活丰富的图形化选项&#xff1b;可以混合…

数分基础(06)商业分析四种类型简介

文章目录 1. 商业分析2. 四种类型2.1 描述性分析和诊断性分析2.1.1 加载Global_Superstore数据集2.1.2 描述性分析2.1.3 诊断性分析2.1.4 再进一步各地区的订单数量和平均订单金额按客户群体分析销售额和利润折扣率和利润产品类别和子类别的销售和利润 本小节小结 2.2 销售预测…

Nature:最大扩散强化学习

转自&#xff1a;清熙 强化学习&#xff08;RL&#xff09;智能体&#xff08;Agent&#xff09;常常很难在现实世界中广泛部署&#xff1a;初始化差异影响大&#xff0c;样本效率低下&#xff0c;情境之外难以泛化。 研究发现问题的关键是违反了数据独立同分布 (iid) 的假设…

驱动(RK3588S)第六课时:linux2.6的使用与GPIO子系统的使用

目录 一、Linux2.6 字符设备驱动编写框架1、合成一个完整的设备号函数2、从完整的设备号里提取主设备号3、动态申请设备号4、静态申请设备号5、释放申请的设备号6、Linux2.6 字符设备驱动的核心结构体7、初始化核心结构体8、向内核去申请 linux2.6 字符设备9、释放申请的设备10…

Linux实验报告2-初步使用shell

目录 一&#xff1a;实验目的 二&#xff1a;实验内容 1 请指出下面每条命令中哪部分是命令名、选项和参数 3 以列表及递归方式查看/dev目录下的文件。 4 修改当前系统时间为2015年1月1日。 7 查看/tmp目录下的所有文件&#xff0c;指出哪些属于隐藏文件。 8 统计文件/e…

Kaggle竞赛:Rossmann Store Sales第66名策略复现

之前做过一次Kaggle的时间序列竞赛数据集练习&#xff1a;CSDN链接效果并不理想&#xff0c;之后在Kaggle的评论中又找到了各式各样的模型方法&#xff0c;其中我还手动还原过第三名的Entity Embedding&#xff1a;CSDN链接。这个参赛方法中&#xff0c;使用了除了比赛给出的数…

MySQL之UDF提权复现

什么是UDF&#xff1a; UDF(Userfined function)用户自定义函数&#xff0c;是MySQL的一个扩展接口&#xff0c;用户通过自定义函数可以实现在 MySQL 中无法方便实现的功能&#xff0c;其添加的新函数都可以在 SQL 语句中调用。 提权条件&#xff1a; 知道MySQL用户名和密码…

探索 Nuxt Devtools:功能全面指南

title: 探索 Nuxt Devtools:功能全面指南 date: 2024/9/3 updated: 2024/9/3 author: cmdragon excerpt: 摘要:本文介绍了Nuxt Devtools的功能和使用方法,包括自动安装、手动安装和各项主要功能,如页面、组件、构建分析等。 categories: 前端开发tags: NuxtDevtools前端…

【AI】Pytorch_损失函数优化器

建议点赞收藏关注&#xff01;持续更新至pytorch大部分内容更完。 本文已达到10w字&#xff0c;故按模块拆开&#xff0c;详见目录导航。 整体框架如下 数据及预处理 模型及其构建 损失函数及优化器 本节目录 损失函数创建损失函数 &#xff08;共18个&#xff09;nn.CrossEnt…

《CounTR: Transformer-based Generalised Visual Counting》CVPR2023

摘要 本论文考虑了通用视觉对象计数问题&#xff0c;目标是开发一个计算模型&#xff0c;用于计算任意语义类别的对象数量&#xff0c;使用任意数量的“样本”&#xff08;即可能为零样本或少样本计数&#xff09;。作者提出了一个新颖的基于Transformer的架构&#xff0c;称为…

【前端面试】leetcode树javascript

写一个树 // 定义二叉树节点 function TreeNode(val, left, right) {this.val = (val === undefined ? 0 : val)this.left = (left === undefined ? null : left)this.right = (right === undefined ? null : right) }// 示例使用 const root = new TreeNode(1,new TreeNod…

Javaweb开发总结(2)

1.处理项目中的异常 利用全局异常处理器 单独创建一个类来处理全局的异常&#xff0c;并对其做出相应回应 /* * 全局异常处理器 * */ RestControllerAdvice public class GlobalExceptionHandler {ExceptionHandler(Exception.class)//代表我们要捕获所有异常public Result ex…

STL-string对字符串进行操作

C形式下的字符串:c_str() string s1("hello"); const char* str s1.c_str(); while (*str) {cout << *str << " ";str; } cout << "\n"; 获取字符数组首地址&#xff0c;用C字符串的形式遍历 区别&#xff1a; cout <…

c++实现生产者消费者的供需关系

一、生产者&消费者模式 生产者-消费者模式&#xff08;Producer-Consumer Pattern&#xff09;是一种常见的并发设计模式&#xff0c;这种模式最常见&#xff0c;所以把它单独拿出来&#xff0c;这种模式用于处理生产者和消费者之间的协调问题。生产者和消费者之间不直接关…