设计模式- 一、设计原则-1

news2024/10/6 6:47:09

一、设计原则

在这里插入图片描述

当涉及到软件设计和开发原则时,有一些常见的原则和准则可以帮助我们编写高质量、可维护和可扩展的代码。以下是其中一些重要的原则和准则:

  1. SOLID原则:

    • 单一职责原则(Single Responsibility Principle,SRP):一个类应该只有一个引起变化的原因,负责一项职责。
    • 开放封闭原则(Open-Closed Principle,OCP):软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。
    • 里氏替换原则(Liskov Substitution Principle,LSP):子类型必须能够替换其基类型而不影响程序的正确性。
    • 接口隔离原则(Interface Segregation Principle,ISP):客户端不应该强迫依赖于它们不需要的接口。
    • 依赖倒置原则(Dependency Inversion Principle,DIP):高层模块不应该依赖于低层模块,二者都应该依赖于抽象。
  2. KISS原则(Keep It Simple, Stupid):保持代码简单易懂,避免过度设计和复杂化,尽量保持代码的简洁性。

  3. DRY原则(Don’t Repeat Yourself):避免重复代码,将重复的逻辑抽象成可复用的组件或函数,提高代码的可维护性和可读性。

  4. 迪米特法则(Law of Demeter,LoD):一个对象应该尽量减少与其他对象之间的直接交互,应该只与其直接朋友进行通信。这样可以降低对象之间的耦合度,提高代码的可维护性和灵活性。

这些原则和准则的目标是提高软件系统的质量、可维护性和可扩展性。它们强调了良好的设计实践和规范,使得代码更具可读性、可测试性和可维护性。

1、单一原则

1.1 简介

单一职责原则(Single Responsibility Principle,简称SRP),它要求一个类或模块应该只负责一个特定的功能

  • 这有助于降低类之间的耦合度,提高代码的可读性和可维护性。
  • 我们可以把模块看作比类更加抽象的概念,类也可以看作模块。或者把模块看作比类更加粗粒度的代码块,模块中包含多个类,多个类组成一个模块。

1.2 例子

案例:

当应用单一责任原则时,我们可以看到代码的模块化和职责分离,每个类或模块专注于一个单一的职责。以下是一个示例,展示了一个简单的订单处理系统,其中有两个类:OrderEmailSender

// 使用单一责任原则的代码示例
public class Order {
    private int orderId;
    private String customerName;
    private double totalAmount;

    public Order(int orderId, String customerName, double totalAmount) {
        this.orderId = orderId;
        this.customerName = customerName;
        this.totalAmount = totalAmount;
    }

    public void processOrder() {
        // 处理订单的逻辑
        // ...

        sendConfirmationEmail();
    }

    private void sendConfirmationEmail() {
        EmailSender emailSender = new EmailSender();
        String message = "Dear " + customerName + ", your order with ID " + orderId + " has been processed.";
        emailSender.sendEmail(customerName, "Order Confirmation", message);
    }
}

public class EmailSender {
    public void sendEmail(String recipient, String subject, String message) {
        // 发送电子邮件的逻辑
        // ...
    }
}

在上述代码中,Order 类负责表示订单,并包含订单的处理逻辑。它的职责是处理订单和发送确认电子邮件。EmailSender 类专门负责发送电子邮件。

这样设计的好处是,Order 类只关注订单的处理逻辑,不涉及与电子邮件发送相关的代码。这遵循了单一责任原则,使得代码更加模块化、可维护和可测试。

现在,让我们看一下如果不遵循单一责任原则会发生什么:

// 没有使用单一责任原则的代码示例
public class Order {
    private int orderId;
    private String customerName;
    private double totalAmount;

    public Order(int orderId, String customerName, double totalAmount) {
        this.orderId = orderId;
        this.customerName = customerName;
        this.totalAmount = totalAmount;
    }

    public void processOrder() {
        // 处理订单的逻辑
        // ...
        
        sendConfirmationEmail();
    }

    private void sendConfirmationEmail() {
        // 发送电子邮件的逻辑
        // ...
    }
}

在上述代码中,Order 类不仅负责订单的处理逻辑,还包含了发送电子邮件的逻辑。这违反了单一责任原则,导致一个类承担了多个职责。

这种设计的问题在于,如果以后需要更改或替换发送电子邮件的方式,需要修改 Order 类中的代码,这可能导致不必要的变更风险,并增加了代码的复杂性。

通过对比这两个示例,我们可以清晰地看到应用单一责任原则的代码更加清晰、可维护和可扩展,每个类或模块只关注一个单一的职责

,避免了不必要的耦合。

好处解析:

当使用单一责任原则的代码需要进行维护时,其好处主要体现在以下几个方面:

  1. 修改订单处理逻辑:假设我们需要修改订单处理逻辑,例如添加一些额外的验证或处理步骤。在使用单一责任原则的代码中,我们只需关注 Order 类中与订单处理逻辑相关的代码,而不必担心影响到与电子邮件发送相关的代码。这样的职责分离使得修改订单处理逻辑变得更加简单和直观。

  2. 替换邮件发送方式:如果我们需要更改或替换邮件发送方式,例如从使用SMTP协议改为使用API调用发送邮件,或者使用不同的邮件服务提供商。在使用单一责任原则的代码中,我们只需关注 EmailSender 类中的邮件发送逻辑,而不必修改 Order 类。这样的职责分离使得替换邮件发送方式变得更加容易和安全。

  3. 测试的简化:由于单一责任原则使得代码更加模块化和职责清晰,因此测试变得更加简单。在使用单一责任原则的代码中,我们可以轻松地针对不同的职责编写独立的单元测试,而不必处理与其他职责相关的复杂逻辑。这样的测试可分离性使得测试更加可靠和可维护。

  4. 降低风险:当需要对代码进行修改时,使用单一责任原则的代码降低了引入错误的风险。因为每个类或模块只关注一个职责,修改其中一个部分不会影响到其他部分,减少了不必要的依赖和耦合。这使得维护过程更加可控和安全。

总之,使用单一责任原则的代码在维护时具有更高的可维护性、可测试性和可扩展性。代码的职责分离使得维护过程更加简化和安全,降低了风险,并促进了代码的模块化和解耦。这使得开发者能够更加轻松地修改、扩展和测试代码,以满足系统的变化需求。

1.3 总结

一个类只负责完成一个职责或者功能。但是也要结合具体的业务。

  • 也就是说,不要设计大而全的类,要设计粒度小、功能单一的类。
  • 换个角度来讲就是,一个类包含了两个或者两个以上业务不相干的功能,那我们就说它职责不够单一,应该将它拆分成多个功能更加单一、粒度更细的类。

2、开闭原则

2.1 简介

开闭原则(pen Closed Principle,简写为 OCP)。它要求应该对扩展开放、对修改关闭

  • 说人话就是,当我们需要添加一个新的功能时,应该在已有代码基础上扩展代码(新增模块、类、方法等),而非修改已有代码(修改模块、类、方法等)

2.2 例子

案例:

如果没有遵循开闭原则,代码可能会如下所示:

class Order {
    private double totalAmount;
    public Order(double totalAmount) {
        this.totalAmount = totalAmount;
    }

    // 计算折扣后的金额
    public double getDiscountedAmount(String discountType) {
        double discountedAmount = totalAmount;
        if (discountType.equals("FESTIVAL")) {
            discountedAmount = totalAmount * 0.9; // 节日折扣,9折
        } else if (discountType.equals("SEASONAL")) {
            discountedAmount = totalAmount * 0.8; // 季节折扣,8折
        }
        return discountedAmount;
    }
}

在这个例子中,订单类 Order 中的 getDiscountedAmount 方法根据不同的折扣类型应用相应的折扣。当需要添加新的折扣类型时,我们不得不修改 getDiscountedAmount 方法的代码,增加新的判断逻辑。

这种设计违反了开闭原则,具有以下不利影响:

  1. 代码的脆弱性:每次添加新的折扣类型时,我们需要修改现有的代码。这增加了代码的脆弱性,因为任何错误的修改都可能导致现有功能的破坏。

  2. 可维护性下降:在没有遵循开闭原则的情况下,代码中的条件逻辑会不断增加,使得代码变得复杂和难以维护。当折扣类型增多时,代码会变得冗长且难以阅读,降低了可维护性。

  3. 扩展困难:由于没有使用抽象和多态来定义折扣策略,我们无法轻松地扩展和添加新的折扣类型。每次需要添加新的折扣类型时,都需要修改现有的代码,这增加了开发的复杂性和风险。

  4. 测试困难:代码中的条件逻辑使得测试变得困难,因为需要编写多个测试用例来覆盖不同的分支。同时,每次修改现有的条件逻辑时,还需要更新相关的测试代码,增加了测试的工作量。

综上所述,如果不遵循开闭原则,代码将变得脆弱、难以维护和扩展。通过引入抽象和多态的设计方式,可以改善代码的可扩展性、可维护性和测试性,使代码更具弹性和适应性。

遵循开闭原则的案例:

在上述代码中,我们可以使用开闭原则对其进行改进。我们可以引入一个抽象的折扣策略接口,每种折扣类型都实现该接口,然后在订单类中使用策略模式来计算折扣金额。

以下是使用开闭原则改进后的代码示例:

// 折扣策略接口
public interface DiscountStrategy {
    double applyDiscount(double totalAmount);
}

// 节日折扣策略
public class FestivalDiscountStrategy implements DiscountStrategy {
    @Override
    public double applyDiscount(double totalAmount) {
        return totalAmount * 0.9; // 节日折扣,9折
    }
}

// 季节折扣策略
public class SeasonalDiscountStrategy implements DiscountStrategy {
    @Override
    public double applyDiscount(double totalAmount) {
        return totalAmount * 0.8; // 季节折扣,8折
    }
}

// 订单类
public class Order {
    private double totalAmount;
    private DiscountStrategy discountStrategy;

    public Order(double totalAmount) {
        this.totalAmount = totalAmount;
    }

    // 设置折扣策略
    public void setDiscountStrategy(DiscountStrategy discountStrategy) {
        this.discountStrategy = discountStrategy;
    }

    // 计算折扣后的金额
    public double getDiscountedAmount() {
        if (discountStrategy != null) {
            return discountStrategy.applyDiscount(totalAmount);
        }
        return totalAmount;
    }
}

在改进后的代码中,我们定义了一个折扣策略接口 DiscountStrategy,并创建了两个具体的折扣策略类 FestivalDiscountStrategySeasonalDiscountStrategy。订单类 Order 中引入了折扣策略,并使用策略模式在 getDiscountedAmount 方法中计算折扣金额。

通过这种方式,当需要添加新的折扣类型时,我们只需要创建一个新的实现了 DiscountStrategy 接口的具体折扣策略类,而不需要修改订单类的代码。我们可以通过设置不同的折扣策略来应用不同的折扣类型。

这样的设计遵循了开闭原则,使得代码更加可扩展和可维护。每个折扣类型都是独立的策略类,可以方便地扩展和修改,而不会对订单类产生影响。这提高了代码的灵活性,并符合开闭原则的设计理念。

2.3 总结

开闭原则是面向对象设计中的重要原则之一:

  • 它要求软件实体(类、模块、函数等)应该对扩展开放,对修改关闭
  • 简单来说,就是在设计中要尽量避免修改已有的代码,而是通过扩展来实现新功能或适应变化的需求。

3、里氏替换原则

3.1简介

里氏替换原则(Liskov Substitution Principle,简写为 LSP):它强调子类型必须能够替换其基类型而不影响程序的正确性

  • 说人话就是,当我们使用继承关系创建派生类(子类)时,这个派生类应该能够无缝替换其基类(父类)的实例,而程序的行为不会出现意外。
  • 这意味着派生类在行为上应该保持与基类的一致性,并且不应该破坏基类的约定,包括输入输出的约束、异常的约束,以及前置条件和后置条件 。
    • 如:尽量不要重写父类的方法。

3.2 例子

案例:

好的,让我们以动物类的例子来说明里氏替换原则的好处和坏处。

假设我们有一个基类 Animal 表示动物,它有一个方法 makeSound() 用于发出声音。然后我们派生出两个子类 DogCat 分别表示狗和猫,它们都继承自 Animal

符合里氏替换原则的例子:

class Animal {
    public void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Dog barks");
    }
}

class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Cat meows");
    }
}

不符合里氏替换原则的例子:

class Animal {
    public void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Dog barks");
    }
}

class Cat extends Animal {
    // 错误:猫不应该重写 makeSound 方法
    @Override
    public void makeSound() {
        throw new UnsupportedOperationException("Cat cannot make sound like a dog");
    }

    // 猫的叫声应该在另一个方法中定义,而不是覆盖基类的方法
    public void meow() {
        System.out.println("Cat meows");
    }
}

调用方法时:

public class Main {
    public static void makeAnimalSound(Animal animal) {
        animal.makeSound();
    }
    public static void main(String[] args) {
        Animal animal1 = new Dog();
        Animal animal2 = new Cat();

        makeAnimalSound(animal1); // Output: "Dog barks"
        makeAnimalSound(animal2); // Output: "Cat meows"
    }
}

当调用 makeAnimalSound 方法时,如果遵循里氏替换原则,输出结果将符合预期,即分别输出 “Dog barks” 和 “Cat meows”。

符合里氏替换原则的情况下:

makeAnimalSound 方法中,我们将 Animal 类型的参数传递进去,并调用其 makeSound() 方法。由于 DogCat 类都是 Animal 类的子类,且它们都重写了 makeSound() 方法,所以在运行时,根据对象的实际类型,会调用相应子类的 makeSound() 方法。

这样做的好处是,我们可以使用统一的方法 makeAnimalSound 来处理不同类型的动物对象,而不需要针对每个具体的子类编写特定的代码。这增加了代码的灵活性和可扩展性,使得我们可以轻松地添加新的动物子类,而不需要修改现有的方法。

不符合里氏替换原则的情况下:

在不遵循里氏替换原则的情况下,当调用 makeAnimalSound 方法时,输出结果可能不符合预期。

在不符合里氏替换原则的示例中,Cat 类重写了 makeSound() 方法,并抛出了一个不支持的操作异常。如果我们将一个 Cat 对象传递给 makeAnimalSound 方法,它将抛出异常而不是输出 “Cat meows”。

这个问题的根本原因是 Cat 类违反了基类 Animal 的行为约定,即 makeSound() 方法应该输出相应动物的声音。这导致代码在处理 Cat 对象时出现了不一致和不可预测的行为。

因此,遵循里氏替换原则可以确保代码在处理父类对象时,不依赖于具体子类的实现细节,而是按照基类的行为约定进行操作。这增加了代码的可靠性、可维护性和可扩展性。相反,违反里氏替换原则可能导致代码的不稳定和不可靠,增加了代码的复杂性和维护成本。

3.3 总结

当遵循里氏替换原则时,子类对象可以完全替换父类对象,并且程序的行为保持一致。这种设计方式具有以下优势:

  1. 可复用性和可扩展性:代码中的父类可以作为通用的抽象接口或基类使用,而子类可以根据需要进行扩展和定制。这样,我们可以使用基类的对象来处理一系列子类对象,而不需要对每个子类编写特定的代码,提高了代码的复用性和可扩展性。

  2. 统一的行为约定:遵循里氏替换原则,子类必须遵循父类的行为约定,确保在任何使用父类对象的地方,都能正确地处理子类对象。这样可以增加代码的可靠性和稳定性,减少意外行为的发生。

  3. 降低代码的耦合性:通过将代码依赖于抽象的父类而不是具体的子类,实现了代码的松耦合。这使得系统更容易理解、修改和扩展,减少了代码之间的依赖关系,提高了代码的可维护性和灵活性。

  4. 符合多态性原则:里氏替换原则是多态性的基础之一。通过将子类对象视为父类对象,实现了多态的特性,可以在运行时根据对象的实际类型来调用相应的方法,增加了代码的灵活性和可扩展性。

总之,里氏替换原则是面向对象设计中的一个重要原则,它强调子类对象必须能够替换其父类对象并且保持系统行为的一致性。遵循该原则可以提高代码的可复用性、可扩展性和可维护性,降低代码的耦合性,并保持多态性的特性。

4、接口隔离原则

4.1 简介

接口隔离原则(Interface Segregation Principle,简称ISP),它强调客户端不应该强迫依赖于它们不需要的接口,其中的“客户端”,可以理解为接口的调用者或者使用者。

  • 说人话就是,当我们设计接口时,应该将其拆分成更小、更具体的接口,以满足客户端的实际需求,而不是设计一个庞大而臃肿的接口。
  • 这样做的好处是,可以提高代码的内聚性,使得类或模块只需实现与其业务相关的接口,而不需要依赖于不相关的接口。同时也降低了类之间的耦合性,提高了代码的灵活性、可维护性和可测试性。

4.2 例子

假设我们正在开发一个机器人程序,机器人具有多种功能,如行走、飞行和工作。我们可以为这些功能创建一个统一的接口:

public interface Robot {
    void walk();
    void fly();
    void work();
}

然而,这个接口并不符合接口隔离原则,因为它将多个功能聚合在了一个接口中。对于那些只需要实现部分功能的客户端来说,这个接口会导致不必要的依赖(如机器人分为:扫地机器人、飞行机器人等)。为了遵循接口隔离原则,我们应该将这个接口拆分成多个更小、更专注的接口:

public interface Walkable {
    void walk();
}

public interface Flyable {
    void fly();
}

public interface Workable {
    void work();
}

现在,我们可以根据需要为不同类型的机器人实现不同的接口。例如,对于一个只能行走和工作的机器人,我们只需要实现 Walkable 和 Workable 接口:

public class WalkingWorkerRobot implements Walkable, Workable {
    @Override
    public void walk() {
        // 实现行走功能
    }
    @Override
    public void work() {
        // 实现工作功能
    }
}

通过遵循接口隔离原则,我们将功能拆分成更小的接口,避免了不必要的依赖关系。现在,客户端只需要依赖于它们真正需要的接口,使得代码更加清晰、可维护和可扩展。如果我们需要新的功能,只需要针对相应的接口进行扩展即可,而不会影响其他接口的实现。这样,我们可以根据需求和场景来选择实现相应的接口,而不需要强制实现不需要的方法。

在实际项目中,应用接口隔离原则可以带来以下好处:

  • 提高代码的内聚性:每个接口只关注特定的功能,使得代码更加专注和可理解。
  • 降低代码的耦合性:客户端只依赖于所需的接口,不受其他不相关接口的影响。
  • 提升代码的灵活性:根据需求选择合适的接口实现,使得系统更加灵活和可扩展。

4.3 总结

接口隔离原则(Interface Segregation Principle,简写为 ISP)强调将大型、笼统的接口拆分成小而精确的接口,以符合客户端的实际需求,避免不必要的依赖和复杂性。

以下是接口隔离原则的总结:

  • 接口应该精确地定义只与特定功能相关的方法,而不是将所有功能都聚合在一个接口中。
  • 将大型接口拆分成多个小接口,每个接口关注特定的功能领域。
  • 客户端应该只依赖于它们真正需要的接口,而不是依赖于不相关的方法。
  • 避免将不需要的方法强加给实现类,防止出现空实现或抛出不支持的操作异常。
  • 接口隔离原则提高了代码的内聚性,使得每个接口和实现类都专注于特定的任务。
  • 通过减少接口之间的依赖,接口隔离原则降低了代码的耦合性,提高了系统的灵活性和可维护性。
  • 合理应用接口隔离原则可以简化系统的设计和维护工作,提升团队的开发效率和协作效果。

总之,接口隔离原则通过细化接口的设计,使得代码更加模块化、可扩展和易于理解。它促进了单一职责原则的实现,提高了代码质量和可维护性。在实际项目中,我们应该根据需求和场景合理应用接口隔离原则,避免过度依赖和冗余代码,构建更灵活、可扩展的系统。


ISP 和 SRP 的区别:

  • 单一职责原则(SRP)要求一个类或模块只负责一项职责或功能。它强调类的内聚性,即一个类应该只有一个引起它变化的原因。SRP的目标是将功能划分清晰,避免一个类承担过多的责任,从而提高代码的可维护性、可测试性和可理解性。

  • 接口隔离原则(ISP)则侧重于接口的设计。它提倡将大型、笼统的接口拆分成小而精确的接口,以符合客户端的实际需求。ISP的目标是避免客户端依赖不需要的方法,减少不相关功能的耦合。通过接口的细化和分离,ISP提高了代码的内聚性,促进了代码模块化、可扩展性和可理解性。

简而言之,**SRP关注类或模块的职责和功能的划分,强调类的单一职责。而ISP关注接口的设计,强调接口的精确性和客户端的需求。**它们共同为代码的可维护性、可测试性和可理解性提供了指导原则,但侧重点和应用场景略有不同。在实际设计中,我们可以同时考虑和应用这两个原则来构建高质量的软件系统。

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

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

相关文章

SpringMVC快速学习

一、SSM框架优化的方向 目录结构&#xff1a; 二、前期文件配置 pom.xml <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 ht…

USB转串口电路—电源与防倒灌设计

USB转串口芯片和串口负载&#xff08;MCU、CPU、其他串口外设等&#xff09;的供电方式可以分为2个大类&#xff1a;统一供电和独立供电。 一、供电说明 统一供电是指USB芯片和串口负载使用同一电源&#xff0c;上下电同步&#xff0c;此时不会存在彼此之间电流倒灌的问题。 …

ORA-01122 ORA-01200故障处理---惜分飞

由于某种原因客户的数据库启动报ORA-01122 ORA-01200错误 让客户把system01.dbf文件发给我进行分析,发现system01.dbf文件大于32G(在8k的blocksize库中,默认情况system01.dbf文件不会超过32G),这个明显异常 检测坏块情况发现4096000之后的block全部为全0块 通过bbed分析文…

数学建模常用模型(二):插值与拟合

数学建模常用模型&#xff08;二&#xff09;&#xff1a;插值与拟合 在数学建模中&#xff0c;插值和拟合是常用的数据分析技术&#xff0c;用于从给定的离散数据中推断出连续函数或曲线的近似形式。 插值是通过已知数据点之间的插值多项式来估计未知数据点的值。插值方法的目…

SQL之收集SQL Server线程等待信息

要知道线程等待时间是制约SQL Server效率的重要原因&#xff0c;这一个随笔中将学习怎样收集SQL Server中的线程等待时间&#xff0c;类型等信息&#xff0c;这些信息是进行数据库优化的依据。 sys.dm_os_wait_stats 这是一个系统视图&#xff0c;里面存储线程所遇到的所有的等…

smart Spring:自定义注解、拦截器的使用(更新中...)

文章目录 〇、使用自定义注解的好处和工作原理一、如何使用自定义注解1.自定义一个注解2.在类、属性、方法上进行使用3.元注解 二、使用拦截器的好处和工作原理三、如何使用拦截器参考 本博客源码&#xff1a; 〇、使用自定义注解的好处和工作原理 自定义注解是Java语言提供的…

消息中间件应用场景

提高系统性能首先考虑的是数据库的优化&#xff0c;但是数据库因为历史原因&#xff0c;横向扩展是一件非常复杂的工程&#xff0c;所有我们一般会尽量把流量都挡在数据库之前。 不管是无限的横向扩展服务器&#xff0c;还是纵向阻隔到达数据库的流量&#xff0c;都是这个思路。…

JSP网上手机商城系统 用eclipse定制开发mysql数据库BS模式java编程jdbc

一、源码特点 JSP 网上手机商城系统是一套完善的web设计系统&#xff0c;对理解JSP java SERLVET mvc编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,eclipse开发&#xff0c;数据库为Mysql5.0&a…

Camera API1 简叙述

目录 一、开启相机 1.1创建项目 1.2注册权限 1.3配置相机特性要求 1.4 获取摄像头的个数 1.5 根据 ID 获取 CameraInfo facing 1.6 开启相机 1.7 关闭相机 二、预览 2.1认识 Parameters 2.2 设置预览尺寸 2.3添加预览 Surface 2.4 开启和关闭预览 2.5 校正预览画…

【电路原理学习笔记】第2章:电压、电流和电阻:2.3 电压

第2章&#xff1a;电压、电流和电阻 2.3 电压 正电荷和负电荷之间存在着吸引力&#xff0c;必须以做功的形式施加一定的能量来克服吸引力&#xff0c;才能使正、负电荷分开一定的距离。所以极性相反的电荷由于它们之间的距离而具有一定的势能。电荷之间的势能之差就称为电位差…

一、枚举类型——新特性(switch 中的 case null)

JDK 17新増了&#xff08;预览&#xff09;功能&#xff0c;可以在 switch 中引入原本非法的 case null。以前只能在 switch 的外部检查是否为 null&#xff0c;如 old() 中所示&#xff1a; CaseNull.java import java.util.function.Consumer;public class CaseNull {static …

Apache Doris 2.0-beta 盲测性能 10 倍提升,更统一的多场景极速分析体验!

亲爱的社区小伙伴们&#xff0c;我们很高兴地向大家宣布&#xff0c;Apache Doris 2.0-beta 版本已于 2023 年 7 月 3 日正式发布&#xff01;在 2.0-beta 版本中有超过 255 位贡献者为 Apache Doris 提交了超过 3500 个优化与修复&#xff0c;欢迎大家下载使用&#xff01; 下…

UE4/5数字人Metahuman与Style3D的使用【三、用数字人进行布料模拟可能出现的两个问题】

目录 接下来我们简单讲解数字人进行的布料模拟 存在的问题一&#xff1a;肩带滑落问题 存在的问题二&#xff1a; 存在的问题三&#xff1a; 关于前面数字人如何操作以及Style3D的相关知识便不在重复&#xff0c;不了解的可以看&#xff1a; UE4/5数字人Metahuman与Style3…

蓝桥杯专题-试题版含答案-【奋斗的小蜗牛】【兰州烧饼】【对决】【画图】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

GitHub 组织是什么?您应该使用一个吗?

GitHub 作为一个平台,被个人程序员和大型组织所使用。无论您与多少人一起工作,“GitHub Organizations”都为管理多个项目的人员提供了一些不错的工具。 GitHub 组织是什么? GitHub Organizations 是 GitHub 的一项功能,允许您创建一个中心位置,团队成员可以在其中访问和…

中国汽车协会:我国整车出口数量达到43.8万辆,同比增长92.8%

根据中国汽车工业协会发布的数据&#xff0c;今年5月份我国汽车整车出口量达到43.8万辆&#xff0c;较上月增长3.2%&#xff0c;同比增长92.8%。 同时&#xff0c;整车出口金额环比增长8.8%&#xff0c;同比增长1.2倍。而今年1-5月&#xff0c;汽车整车出口量达到193.3万辆&…

杂记 | 使用idea构建SpringBoot项目并远程连接docker运行

文章目录 概述01 连接远程docker02 本地打包03 创建dockerfile文件04 部署并运行 概述 使用docker运行SpringBoot项目是一个不错的选择&#xff0c;传统方式需要手动打包并上传到服务器&#xff0c;在使用docker build构建镜像&#xff0c;再使用docker run启动运行&#xff0…

Flutter 父子组件互调方法

Flutter 父子组件互调方法 文章目录 Flutter 父子组件互调方法一、父组件调用子组件方法1、概述2、代码实现3、效果 二、子组件调用父组件方法1、概述2、代码实现3、效果 一、父组件调用子组件方法 1、概述 使用 GlobalKey&#xff1a;可以为子组件创建一个 GlobalKey 对象&a…

HOT44-二叉搜索树中第K小的元素

leetcode原题链接&#xff1a;二叉搜索树中第K小的元素 题目描述 给定一个二叉搜索树的根节点 root &#xff0c;和一个整数 k &#xff0c;请你设计一个算法查找其中第 k 个最小元素&#xff08;从 1 开始计数&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,1…

U-Boot移植 (2)- LCD 驱动修改和网络驱动修改

文章目录 1. LCD 驱动修改1.1 修改c文件配置1.2 修改h文件配置1.3 编译测试 2. 网络驱动修改2.1 I.MX6U-ALPHA 开发板网络简介2.2 网络 PHY 地址修改2.3 删除 uboot 中 74LV595 的驱动代码2.4 添加开发板网络复位引脚驱动2.5 更新 PHY 的连接状态和速度2.6 烧写调试2.7 测试一下…