探索设计模式的魅力:一篇文章让你彻底搞懂建造者模式

建造者模式(Builder Pattern)是一种创建型设计模式,旨在将一个复杂对象的创建过程与其表示分离,使得同样的构建过程可以创建不同的表示形式。

        

主要角色:

  1. 产品(Product):表示正在构建的复杂对象。它由多个部分组成,这些部分可能具有不同的特性和属性。

  2. 抽象建造者(Abstract Builder):定义了构建产品所需的各个步骤抽象接口。每个步骤都有具体的实现方法,用于构建产品的不同部分。通常,抽象建造者还提供一个获取最终生成产品的方法。

  3. 具体建造者(Concrete Builder):实现了抽象建造者接口,负责实际构建产品的各个部分。具体建造者通常具有一个内部变量来保存当前产品的状态。构建过程中,具体建造者负责跟踪和更新产品的状态。

  4. 指挥者(Director):负责按特定顺序调用具体建造者的方法,以完成产品的构建过程。指挥者知道构建者应该如何构建产品,但不关心具体的构建细节。它通过接收具体建造者对象,按照预定的顺序调用构建步骤,最终获取完成的产品。

实现步骤:

  1. 定义产品类(Product):首先,定义一个需要被构建的复杂对象的类,这个类通常包含多个属性。

  2. 创建抽象建造者接口(Builder):建造者接口定义了用于构建产品的方法,这些方法包括设置产品的属性等。

  3. 创建具体建造者类(ConcreteBuilder):针对产品类实现抽象建造者接口,实现产品的各个部件的具体构造过程,以及提供获取最终产品的方法。

  4. 创建指挥者类(Director):指挥者类负责使用建造者接口来构建产品。它不直接构建产品,而是通过调用建造者接口中的方法来构建产品。

  5. 使用建造者模式:客户端代码通过指挥者类来构建产品,指挥者将构建过程委托给具体的建造者类,最终得到构建好的产品。

优点:

  1. 分离构建过程和最终表示:建造者模式可以将产品的构建过程与表示分离,使得相同的构建过程可以得到不同的表示。
  2. 易于扩展:通过建造者模式,可以很容易地扩展和改变产品的内部表示,使得我们可以更灵活地修改构建过程。
  3. 隐藏细节:客户端不需要关心产品的构建细节,只需关心最终的产品对象的使用即可。
  4. 构建复杂对象:对于构建具有复杂内部结构的对象来说,建造者模式可以使得构建过程更清晰、更易于维护。

缺点:

  1. 增加代码量:引入了建造者模式会增加代码量,特别是当产品的属性比较多,需要通过建造者类逐一设置时,会显得比较繁琐。
  2. 可能会导致产生多余的建造者对象:如果产品的构建过程比较简单,引入建造者模式可能会显得有些多余。

     客户端(Client):创建指挥者对象并配置具体建造者,然后通过指挥者获取最终构建完成的产品。客户端可以根据需要选择不同的具体建造者或使用自定义的建造者。客户端只需要关心如何使用最终构建完成的产品。

     建造者模式允许按照一系列步骤来构建对象,而不需要暴露复杂对象的构建过程。这种分步骤的构建方式使得构建过程更加灵活和可扩展,并且可以轻松地创建不同组合的对象。此外,建造者模式还可以避免创建过多的构造函数或重叠参数的问题。

     建造者模式可以有效地解耦复杂对象的构建过程,提高灵活性和可维护性,同时还可以支持创建不同表示形式的产品。

目录

一、案例

 1.1 示例代码

 1.2 用建造者模式重写示例

二、模式讲解

 2.1 功能

 2.2 建造者模式的结构和说明

 2.3 建造者模式重写代码的结构图

 2.4 建造者模式的调用顺序示意图

 3.5 相关模式

  3.5.1 建造者模式和组合模式

  3.5.2 建造者模式和模板方法模式

  3.5.3 建造者模式和工厂方法模式

  3.5.4 建造者模式与工厂模式

三、建造者模式结合抽象工厂模式

 3.1 结合抽象工厂模式代码实现

 3.2 练习


一、案例

     在工厂模式中,我们抽象了工厂,客户端通过创建的工厂来实例化对应的产品。假设产A、产品B和 产品C 是流水线产品,流水线步骤一样(假设固定组装手机顺序:主板 -> 电池 -> 外壳 -> 调试 -> 包装),这时,工厂模式无法满足这种场景。

     用建造者模式抽象流水线步骤实现。

 1.1 示例代码

     产品类:

class Product {
    // 产品的属性
    // ...
}

     抽象建造者接口:

interface Builder {
    void buildPart1();
    void buildPart2();
    Product getResult();
}

     具体建造者类:

class ConcreteBuilder implements Builder {

    private Product product = new Product();
    
    public void buildPart1() {
        // 构建产品的第一个部分
        // ...
    }
    public void buildPart2() {
        // 构建产品的第二个部分
        // ...
    }
    public Product getResult() {
        return this.product;
    }
}

     指挥者:

class Director {
    private Builder builder;
    
    public Director(Builder builder) {
        this.builder = builder;
    }
    
    public Product construct() {
        this.builder.buildPart1();
        this.builder.buildPart2();
        return this.builder.getResult();
    }
}

     客户端:

public class Client {
    public static void main(String[] args) {
        Builder builder = new ConcreteBuilder();
        Director director = new Director(builder);
        Product product = director.construct();
    }
}

         

 1.2 用建造者模式重写示例

      产品类:(两个产品:小米和苹果)

@Data
public class XiaomiPhoneProduct {

    private String name = "小米";
}
@Data
public class ApplePhoneProduct {

    private String name = "苹果";
}

     抽象建造者接口:

public interface Builder {
    /**
     * 组装主板
     */
    void assembleMainboard();
    /**
     * 组装电池
     */
    void assembleBattery();
    /**
     * 组装外壳
     */
    void assembleOuter();
    /**
     * 调试
     */
    void assembleDebugging();
    /**
     * 包装
     */
    void assemblePack();

}

     小米建造者类:

public class XiaoMiBuilder implements Builder {

    private XiaomiPhoneProduct xm = new XiaomiPhoneProduct();

    @Override
    public void assembleMainboard() {
        System.out.println("组装" + xm.getName() + "产品的 主板。");
    }

    @Override
    public void assembleBattery() {
        System.out.println("组装" + xm.getName() + "产品的 电池。");
    }

    @Override
    public void assembleOuter() {
        System.out.println("组装" + xm.getName() + "产品的 外壳。");
    }

    @Override
    public void assembleDebugging() {
        System.out.println("调试" + xm.getName() + " 产品。");
    }

    @Override
    public void assemblePack() {
        System.out.println("包装" + xm.getName() + " 产品。");
    }

    public XiaomiPhoneProduct getResult() {
        System.out.println("获取" + xm.getName() + "产品");
        return xm;
    }
}

     苹果建造者类:

public class AppleBuilder implements Builder {

    private ApplePhoneProduct apple = new ApplePhoneProduct();

    @Override
    public void assembleMainboard() {
        System.out.println("组装" + apple.getName() + "产品的 主板。");
    }

    @Override
    public void assembleBattery() {
        System.out.println("组装" + apple.getName() + "产品的 电池。");
    }

    @Override
    public void assembleOuter() {
        System.out.println("组装" + apple.getName() + "产品的 外壳。");
    }

    @Override
    public void assembleDebugging() {
        System.out.println("调试" + apple.getName() + " 产品。");
    }

    @Override
    public void assemblePack() {
        System.out.println("包装" + apple.getName() + " 产品。");
    }

    public ApplePhoneProduct getResult() {
        System.out.println("获取" + apple.getName() + "产品");
        return apple;
    }
}

     指挥者:

public class Director {

    private Builder builder;

    public Director(Builder builder) {
        this.builder = builder;
    }

    public void construct() {
        // 组装主板
        this.builder.assembleMainboard();
        // 组装电池
        this.builder.assembleBattery();
        // 组装电池
        this.builder.assembleOuter();
        // 调试
        this.builder.assembleDebugging();
        // 包装
        this.builder.assemblePack();
    }
}

     客户端:

public class Client {

    public static void main(String[] args) {
        XiaoMiBuilder xiaoMiBuilder = new XiaoMiBuilder();
        Director director1 = new Director(xiaoMiBuilder);
        // 组装小米手机产品
        director1.construct();
        // 获取小米手机
        XiaomiPhoneProduct result1 = xiaoMiBuilder.getResult();

        AppleBuilder appleBuilder = new AppleBuilder();
        Director director2 = new Director(appleBuilder);
        // 组装苹果手机产品
        director2.construct();
        // 获取苹果手机
        ApplePhoneProduct result2 = appleBuilder.getResult();
    }
}

      测试支行:

组装小米产品的 主板。
组装小米产品的 电池。
组装小米产品的 外壳。
调试小米 产品。
包装小米 产品。
获取小米产品
组装苹果产品的 主板。
组装苹果产品的 电池。
组装苹果产品的 外壳。
调试苹果 产品。
包装苹果 产品。
获取苹果产品

        通过上面的 讲述,应该能很清晰地看出建造者模式的实现方式和它的优势所在了,那就是对同 一个 构建过程,只要配置不同的建造者实现,就会生成不同表现的对象。

        

二、模式讲解

建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的 表示。

建造者模式的本质:分离整体构建算法和部件构造。

 2.1 功能

功能:构建复杂的产品,而且是细化的、分步骤的构建产品,也就是建造者模式重在 一步 一步解决构造复杂对象的问题。不只为此,更为重要的是,这个构建的过程是统一的、固定不变的,变化的部分放到建造者部分了,只要配置不同的建造者,那么同样的构建过程,就能构建出不同的产品来。

        

 2.2 建造者模式的结构和说明

  • Builder:建造者接口,定义创建 一个Product 对象所需的各个部件的操作。
  • ConcreteBuilder:具体的建造者实现,实现各个部件的创建,并负责组装Product对象的各个部件,同时还提供一个让用户获取组装完成后的产品对象的方法。
  • Director:指导者,也被称为导向者,主要用来使用Builder 接口,以一个统一的过程来构建所需要的Product 对象。
  • Product:产品,表示被建造者构建的复杂对象,包含多个部件。

        

 2.3 建造者模式重写代码的结构图

     建造者模式主要用于以下几个方面的应用场景中:

  1. 构建复杂对象:当需要构建的对象具有复杂的内部结构,并且需要通过多个步骤逐步构建时,可以使用建造者模式。它可以将构建过程划分为多个步骤,每个步骤由具体的建造者来实现,从而更加灵活地构建复杂对象。

  2. 需要隐藏对象构建过程的细节:使用建造者模式可以将对象的构建细节隐藏起来,只向客户端暴露一个简单的构建接口。客户端不需要关心对象的具体构建过程,只需通过指挥者类来构建对象。

  3. 构建对象的部分属性可变:如果需要构建的对象具有一些可变的属性,而且构建过程中需要根据特定的需求来设置这些属性,可以使用建造者模式。建造者模式可以通过具体的建造者类,根据不同的需求来设置不同的属性值。

  4. 构建多个相似对象:如果有多个类似的对象需要构建,但是它们的构建过程略有不同,可以使用建造者模式。可以提供多个具体的建造者类来分别构建不同的对象,从而更好地组织和管理对象的构建过程。

     优势:

  1. 简化对象的创建过程:通过建造者模式,可以将复杂对象的创建逻辑分解为多个步骤,使得构建过程更加清晰和可控。每个步骤都有对应的方法,在客户端代码中可以按需调用,不必关心具体的创建细节。

  2. 可以更灵活地构建对象:通过建造者模式,可以使用相同的构建过程来构建不同的产品。通过定义不同的具体建造者,可以创建具有不同属性配置的对象,而不会混淆或混合构建逻辑。

  3. 隐藏产品构建细节:客户端不需要了解产品的具体构建过程,可以直接通过指定建造者的方法来创建产品。这样可以减少客户端对产品内部细节的依赖,同时也可以隐藏产品内部的实现细节。

  4. 提供了更好的封装性:建造者模式将产品的创建过程封装在具体建造者中,客户端只需要调用指定的方法获取产品,而无需了解建造的细节。这种封装性可以减少对产品内部实现的直接访问,提高了代码的封装性和安全性。

  5. 支持逐步构建复杂对象:通过建造者模式,可以分步骤构建复杂对象。在每个步骤中,可以对对象进行逐渐完善和扩展,从而满足不同的需求和变化。

  6. 松散耦合:建造者模式可以用同一个构建算法构建出表现 上完全不同的产品,实现产品构建和产品表现 上的分离。建造者模式正是把产品构建的过程独立出来,使它和具体产品的表现松散耦合,从而使得构建算法可以复用,而具体产品表现也可以灵活地、方便地扩展和切换。

  7. 可以很容 易地改变产 品的内部表示:在建造者模式中,由 于Builder 对象只是提供接口给Director 使用,那么具体的部件创建和装配方式是被Builder 接口隐藏了的,Director 并不知道这些具体的实现细节。这样一来,要想改变产品的内部表示,只需要切换Builder 的具体实现即可,不用管Director,因此变得很容易。

  8. 更好的复用性:建造者模式很好地实现了构建算法和具体产品实现的分离。这样一来,使得构建产品的算法可以复用。同样的道理,具体产品的实现也可以复用,同一个产品的实现,可以配合不同的构建算法使用。

     不足:

  1. 类的膨胀:使用建造者模式会引入额外的建造者类,导致类的数量增加。对于简单的对象,引入建造者模式可能会显得过度复杂。

  2. 对象内部结构的暴露:在一些情况下,建造者模式会要求产品对象暴露其内部结构,以便建造者能够逐步构建对象。这可能违反封装原则,并使得产品对象的内部结构对外暴露,降低了对象的安全性。

  3. 对象构建流程的不可逆转:一旦对象的构建过程开始,建造者模式往往不支持将构建过程逆转。一旦开始构建,很难回到前一个步骤进行修改。

  4. 不适合每个场景:建造者模式在对象的属性较多、复杂度较高,且对象的创建过程中涉及较多的选项和步骤时非常有用。但对于简单的对象,使用建造者模式可能会带来过多的额外复杂性。

  5. 学习和实现成本:建造者模式的实现需要定义产品类、抽象建造者、具体建造者等多个类,这可能带来额外的学习和实现成本,特别是对于初学者而言。

        

 2.4 建造者模式的调用顺序示意图

         

 3.5 相关模式

  3.5.1 建造者模式和组合模式

     这两个模式可以组合使用。

     对于复杂的组合结构,可以使用建造者模式来一步一步构建。

         

  3.5.2 建造者模式和模板方法模式

     模板方法模式主要是用来定义算法的骨架,把算法中某些步骤延迟到子类中实现。再想起建造者模式 ,Director 用来定义整体的构建算法,把算法中某些涉及到具体部件对象的创建和装配的功能,委托给具体的Builder 来实现。

     类似:

  • 都是定义一个固定的算法骨架,然后把算法中的某些具体步骤 交给其他类来完成,都能 实现整体算法步骤和某些具体 步骤实现的分离。

     区别:

  • 模式的目的:建造者模式是用来构建复杂对象的,而模板方法是用来定义算法骨架,尤其是一些复杂的业务功能的处理算法的骨架;
  • 模式的实现:建造者模式是采用委托的方法,而模板方法采用的是继承的方式; 
  • 使用的复杂度:建造者模式需要组合 Director 和Builder 对象,然后才能开始构建,要等构建完后才能得最终的对象,而模板方法就没有这么麻烦,直接使用子类对象即可。

        

  3.5.3 建造者模式和工厂方法模式

     这两个模式可以组合使用。

     建造者模式的Builder 实现中,通常需要选择具体的部件实现。一个可行的方案就是实现成为工厂方法,通过工厂方法来获取具体的部件对象,然后再进行部件的装配。

        

  3.5.4 建造者模式与工厂模式

  1. 关注点不同:
  • 工厂模式关注于创建对象的过程,即根据客户端请求创建相应的对象实例;
  • 建造者模式关注于构建复杂对象的过程,即通过一步步构建的方式创建对象。

  2. 设计目的不同:

  • 工厂模式旨在解耦对象的创建和使用,在客户端和具体实现之间建立一个工厂类,通过工厂方法创建所需的对象实例;
  • 建造者模式旨在通过一步步构建来创建一个复杂对象,也可以通过一系列构建步骤来定义不同的表示。

  3. 灵活性不同:

  • 工厂模式具有较高的灵活性,可以根据不同的需求创建不同类型的对象,且可以动态切换具体实现;
  • 建造者模式相对固定,通常使用一个具体的构造类,按照固定步骤构建对象,不太容易切换。

  4. 构建过程不同:

  • 工厂模式的创建过程相对简单,仅涉及对象的实例化,没有复杂的构建过程;
  • 建造者模式涉及多个步骤,每个步骤可以定制和配置,可以支持不同对象的创建。

        

三、建造者模式结合抽象工厂模式

     回顾抽象工厂模式:

探索设计模式的魅力:抽象工厂模式的艺术-CSDN博客文章浏览阅读3.1k次,点赞67次,收藏68次。抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,用于在不指定具体类的情况下创建一系列相关或相互依赖的对象。它提供了一个接口,用于创建一系列“家族”或相关依赖对象,而无需指定它们的具体类。探索设计模式的魅力:简单工厂模式-CSDN博客实现简单工厂的难点就在于 “如何选择” 实现,前面便子中传递参数的方法, 那都是静态的参数,还可以实现成为动态的参数。https://blog.csdn.net/danci_/article/details/135638488

     抽象工厂模式和建造者模式可以结合使用,以实现更复杂的对象创建过程。 

 3.1 结合抽象工厂模式代码实现

     抽象工厂模式用于创建相关或依赖的对象族,而建造者模式用于创建复杂对象的构建过程。下面是一个示例,演示如何结合抽象工厂模式和建造者模式:

     首先,定义产品族的抽象工厂接口,用于创建产品族中的不同类型产品。例如,我们可以创建一个汽车工厂接口来生产不同类型的汽车及其相关零部件。

public interface CarFactory {
    Engine createEngine();
    Wheel createWheel();
    // 其他相关方法
}

     然后,定义具体的产品族工厂类,实现抽象工厂接口,并负责创建特定类型的产品。例如,我们可以创建一个奔驰汽车工厂类和一个宝马汽车工厂类。

public class BenzFactory implements CarFactory {
    @Override
    public Engine createEngine() {
        return new BenzEngine();
    }

    @Override
    public Wheel createWheel() {
        return new BenzWheel();
    }
    // 其他相关方法实现
}

public class BMWFactory implements CarFactory {
    @Override
    public Engine createEngine() {
        return new BMWEngine();
    }

    @Override
    public Wheel createWheel() {
        return new BMWWheel();
    }
    // 其他相关方法实现
}

     接下来,定义产品的抽象建造者接口,用于创建复杂对象。例如,我们可以创建一个汽车建造者接口来构建汽车对象。

public interface CarBuilder {
    void buildEngine();
    void buildWheel();
    // 其他构建方法
    Car getCar();
}

     然后,定义具体的产品建造者类,实现抽象建造者接口,并负责实际构建复杂对象的各个部分。例如,我们可以创建一个汽车建造者类来构建汽车对象。

public class CarBuilderImpl implements CarBuilder {
    private Car car;

    public CarBuilderImpl() {
        this.car = new Car();
    }

    @Override
    public void buildEngine() {
        // 构建引擎部分的具体逻辑
        // car.setEngine(...);
    }

    @Override
    public void buildWheel() {
        // 构建轮子部分的具体逻辑
        // car.setWheel(...);
    }

    // 其他构建方法的具体实现

    @Override
    public Car getCar() {
        return car;
    }
}

     最后,在客户端中使用抽象工厂模式和建造者模式来创建复杂对象。

public class Client {
    public static void main(String[] args) {
        // 创建奔驰汽车工厂
        CarFactory benzFactory = new BenzFactory();

        // 创建汽车建造者
        CarBuilder builder = new CarBuilderImpl();

        // 设置建造者为奔驰工厂
        builder.setCarFactory(benzFactory);

        // 建造汽车并获取
        Car car = builder.buildCar();

        // 使用创建好的汽车
        car.drive();
    }
}

     在这个例子中,我们通过抽象工厂模式创建了一个奔驰汽车工厂和一个宝马汽车工厂,并通过建造者模式创建了一个汽车对象。通过结合抽象工厂模式和建造者模式,我们可以实现更复杂的对象构建过程,并根据具体情况创建不同类型的对象。

        

 3.2 练习

     回顾工厂方法模式:

探索设计模式的魅力:工厂方法模式-CSDN博客文章浏览阅读6.3k次,点赞104次,收藏71次。工厂方法模式是一种创建型设计模式,它提供了一种创建对象的接口,但将具体实例化对象的工作推迟到子类中完成。这样做的目的是创建对象时不用依赖于具体的类,而是依赖于抽象,这提高了系统的灵活性和可扩展性。优点:降低耦合度、增加了系统的可扩展性 和 提高代码的可维护性;缺点:增加了代码的复杂性 和 需要更多的设计考虑。https://blog.csdn.net/danci_/article/details/135611783     请编程实现建造者模式结合工厂方法模式。

        

PS:感谢您耐心看到了这里,再麻烦动动发财的手,点个赞点个赞点个赞吧!(关注收藏也是免费的哦)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

git提权

实验环境——vulnhub-dc2靶场 git提权 前提:用户可以使用sudo中git权限 查看sudo权限 sudo -l可以发现git命令存在sudo提权 基于此进行权限提升 方式: sudo git help config #在末行命令模式输入 !/bin/bash 或 !sh #完成提权 sudo git -p help…

海外问卷调查怎么做?

大家好,我是橙河老师,我自己做海外问卷项目已经2年时间了,一般来说互联网项目的生命周期都不会太长,但海外问卷项目是一个稳定长期可做的项目,只要消费市场一直存在,问卷调查的需求就不会消失,我…

DBA技术栈MongoDB:简介

1.1 什么是MongoDB? MongoDB是一个可扩展、开源、表结构自由、用C语言编写且面向文档的数据库,旨在为Web应用程序提供高性能、高可用性且易扩展的数据存储解决方案。 MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当…

深度学习记录--偏差/方差(bias/variance)

误差问题 拟合神经网络函数过程中会出现两种误差:偏差(bias)和方差(variance) 偏差和误差的区别 欠拟合(underfitting) 当偏差(bias)过大时,如左图,拟合图像存在部分不符合值,称为欠拟合(underfitting) 过拟合(overfitting) …

gitlab 部署项目新分支

公司代码管理平台新切换到gitlab下,上线发版流程随之变更 1新建分支,开发完成,提交新分支 2.去gitlab平台上找到Merge requests 3 点击右上角的New merge request select source branch 选择新建的分支 点击 compare branches and contin…

python222网站实战(SpringBoot+SpringSecurity+MybatisPlus+thymeleaf+layui)-热门标签推荐显示实现

锋哥原创的SpringbootLayui python222网站实战: python222网站实战课程视频教程(SpringBootPython爬虫实战) ( 火爆连载更新中... )_哔哩哔哩_bilibilipython222网站实战课程视频教程(SpringBootPython爬虫实战) ( 火…

Wayfair 开启2024年的裁员模式

周五的时候 Wayfair 的 CEO 公开信中表示,将削减 1650 个工作岗位。 通篇读下来的意思就是公司目前还是非常健康的状态,新冠导致的在线购物激增让 Wayfair 在短时间内的销售从 90 亿美元增加到 180 亿美元。 几乎是翻倍了,而且这个让 Wayfai…

python222网站实战(SpringBoot+SpringSecurity+MybatisPlus+thymeleaf+layui)-帖子详情页实现

锋哥原创的SpringbootLayui python222网站实战: python222网站实战课程视频教程(SpringBootPython爬虫实战) ( 火爆连载更新中... )_哔哩哔哩_bilibilipython222网站实战课程视频教程(SpringBootPython爬虫实战) ( 火…

Midjourney网页版

引言 基于国外的api开发开发了一款网页版的midjourney,文末有链接 相关资源 Midjourney官方教学资料Midjourney官网discord官网B站学习资源推荐 账号注册 获取网络访问权限 使用Midjourney的前提是计算机有外网访问权限 此处推荐两款软件,lantern的优势是免费&…

【正点原子STM32连载】 第四十五章 内存管理实验 摘自【正点原子】APM32E103最小系统板使用指南

1)实验平台:正点原子APM32E103最小系统板 2)平台购买地址:https://detail.tmall.com/item.htm?id609294757420 3)全套实验源码手册视频下载地址: http://www.openedv.com/docs/boards/xiaoxitongban 第四…

Spring Security的使用条件

Spring Security要求使用Java 8或更高版本的运行时环境。 由于Spring Security旨在以自包含的方式运行,因此您无需在Java运行时环境中放置任何特殊的配置文件。特别是,您无需配置特殊的Java认证和授权服务(JAAS)策略文件&#xf…

仿真机器人-深度学习CV和激光雷达感知(项目2)day03【机器人简介与ROS基础】

文章目录 前言机器人简介机器人应用与前景机器人形态机器人的构成 ROS基础ROS的作用和特点ROS的运行机制ROS常用命令 前言 💫你好,我是辰chen,本文旨在准备考研复试或就业 💫本文内容是我为复试准备的第二个项目 💫欢迎…

C++ memcpy函数学习以及和strcpy的不同

memcpy指的是C和C++使用的内存拷贝函数,函数原型为, void *memcpy(void *destin, void *source, unsigned n); 函数的功能是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源source中拷贝n个字节到目标destin中。 // castdemo.cpp : Defines the entry p…

【PyTorch】PyTorch之Reduction Ops

文章目录 前言一、ARGMAX二、ARGMIN三、AMAX和AMIN四、ALL和ANY五、MAX和MIN六、MEAN七、MEDIAN八、NORM九、PROD十、STD十一、SUM十二、UNIQUE十三、VAR 前言 介绍pytorch的Reduction Ops。 一、ARGMAX torch.argmax(input, dim, keepdimFalse) → LongTensor Parameters&a…

掌握使用CXF快速开发webservice服务和生成client端技能

文章目录 前言1.安装和配置cxf环境2.创建一个通过maven管理的java项目并引入相关cxf依赖3.使用cxf提供的类编写webservice服务端并发布服务3.1 定义一个webservice服务接口HelloWorld3.2 编写HelloWorld实现类3.3 通过JaxWsServerFactoryBean发布webservice服务3.4 在浏览器中通…

游戏开发制作过程

游戏开发是一门结合艺术、技术和创意的复杂工艺。从一个简单的想法到一个完全实现的游戏,这个过程是多层次的,每一步都至关重要。在这篇文章中,我们将探索游戏开发的各个阶段,从概念化到最终发布。 游戏开发的第一步是将一个抽象的…

AI 编程的机会和未来:从 Copilot 到 Code Agent

大模型的快速发展带来了 AI 应用的井喷。统计 GPT 使用情况,编程远超其他成为落地最快、使用率最高的场景。如今,大量程序员已经习惯了在 AI 辅助下进行编程。数据显示,GitHub Copilot 将程序员工作效率提升了 55%,一些实验中 AI …

Java 读取 Excel 表格—— Easy Excel 基本使用

两种读对象的方式 确定表头&#xff1a;建立对象&#xff0c;和表头形成映射关系。不确定表头&#xff1a;每一行数据映射为 Map<String, Object>&#xff0c;比如用户自己上传的表格。 两种读取模式 监听器&#xff1a;先创建监听器、在读取文件时绑定监听器。单独抽…

vue2 使用pdf.js 实现pdf预览,并可复制文本

需求&#xff1a;pdf预览&#xff0c;并且可以选中pdf的内容进行复制。 在ruoyi的vue前端项目中用到&#xff0c;参考了网上不少文章&#xff0c;因为大部分没给具体的pdf.js版本&#xff0c;导致运行过程中报各种api 错误&#xff0c;经过尝试以下版本可用&#xff0c…

2023全球边缘计算大会深圳站:核心内容与学习收获(附大会核心PPT下载)

边缘计算作为当今IT领域的热门话题&#xff0c;已经引起了全球范围内的广泛关注。本次大会汇聚了众多业界精英&#xff0c;共同探讨边缘计算的发展趋势、技术应用与创新实践。本文将围绕大会的核心内容展开讨论&#xff0c;并分析参会者从中能够学到的东西。 一、边缘计算的发…