【6大设计原则】精通设计模式之里氏代换原则:从理论到实践,掌握代码演化的黄金法则

news2024/11/26 4:52:56

一、引言

1.1 设计模式的必要性

在软件开发的复杂性面前,设计模式提供了一套成熟的解决方案,它们是经过多年实践总结出来的,能够帮助我们应对各种编程难题。设计模式不仅仅是一种编程技巧,更是一种编程哲学,它能够提高代码的可读性、可维护性和可扩展性,使代码更加健壮。在现代软件开发中,不懂设计模式就像不懂语法一样,是难以想象的。

1.2 六大设计原则简介

在这里插入图片描述

六大设计原则是面向对象设计的基础,它们是:单一职责原则、开放封闭原则、里氏代换原则、接口隔离原则、依赖倒置原则和迪米特法则。这些原则是面向对象设计的核心,掌握它们能够使我们的代码更加简洁、清晰、易于维护。每一条原则都有其深刻的含义和实际的应用场景,是软件设计中不可或缺的指导方针。

1.3 里氏代换原则的重要性

里氏代换原则是面向对象设计中最重要的原则之一,它要求我们在设计类的时候,要遵循一条基本规则:子类必须能够替换掉它们的基类,而不会引起程序的非预期行为。这条原则看似简单,实则包含了深刻的含义。它不仅是实现开闭原则的基础,也是实现其他设计原则的前提。通过遵循里氏代换原则,我们可以创建出更加灵活、可扩展的代码结构,使代码更加符合面向对象的设计理念。

二、里氏代换原则理论解析

在这里插入图片描述

2.1 定义与内涵

里氏代换原则(Liskov Substitution Principle, LSP)是由Bertrand Meyer提出的面向对象设计的基本原则之一。它规定:如果S是一个类,那么任何S的子类都应当是S的一个实例的“替代品”。这意味着,在程序中,我们应该能够用子类对象替换掉基类对象,而不会导致程序的行为出现异常。换句话说,基类的方法应该被设计成能够被其子类的所有实例所替换,而不需要修改代码。

2.2 原理与动机

里氏代换原则的原理在于,它鼓励我们在设计类时,应该关注类的抽象,而不是具体的实现。这样,当我们需要对类进行扩展时,就可以通过创建新的子类来完成,而不是直接修改基类。这种设计方式有助于减少代码的耦合度,提高代码的可维护性和可扩展性。

动机的背后是面向对象设计中的一个基本矛盾:一方面,我们希望类的功能是封闭的,即一个类应该只关注自己的业务逻辑,而不关心其他类的细节;另一方面,我们希望类的功能是可扩展的,即在不修改原有代码的情况下,能够方便地对类进行扩展。里氏代换原则正是为了解决这个矛盾而提出的。

2.3 面向对象的基本概念

为了更好地理解里氏代换原则,我们需要回顾一些面向对象的基本概念:

  • 类(Class):类是对象的蓝图,它定义了一组属性(称为“字段”)和方法(称为“行为”)。
  • 对象(Object):对象是类的实例,它具有类定义的属性和方法。
  • 继承(Inheritance):继承是面向对象编程中的一个核心概念,它允许我们创建一个新的类(子类),该类继承了另一个类(基类)的属性和方法。
  • 子类(Subclass):子类是继承自某个基类的类,它继承了基类的所有属性和方法,并可以添加新的属性和方法,或者覆盖基类的方法。
  • 基类(Base Class):基类是被继承的类,它提供了子类可以继承的属性和方法。

通过理解这些基本概念,我们可以更好地理解里氏代换原则的重要性,以及如何在实际编程中应用它。在下一节中,我们将通过具体的代码实例来演示里氏代换原则的应用。

三、里氏代换原则实例解析

3.1 案例一:违反里氏代换原则的代码

在这个案例中,我们将看到一个违反里氏代换原则的类设计。假设我们有一个形状接口,以及两个实现该接口的类:圆形和正方形。我们希望通过形状接口来操作这些形状,但是,如果我们的代码是这样实现的:

public interface Shape {
    double getArea();
}

public class Circle implements Shape {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    public double getArea() {
        return Math.PI * radius * radius;
    }
}

public class Rectangle implements Shape {
    private double width;
    private double height;

    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    public double getArea() {
        return width * height;
    }
}

// 使用形状接口操作形状
public class ShapeOperations {
    public void draw(Shape shape) {
        System.out.println("Drawing " + shape.getClass().getSimpleName());
    }
}

public class Main {
    public static void main(String[] args) {
        ShapeOperations operations = new ShapeOperations();
        Circle circle = new Circle(5);
        Rectangle rectangle = new Rectangle(4, 5);

        operations.draw(circle);
        operations.draw(rectangle);
    }
}

在这个例子中,ShapeOperations 类有一个 draw 方法,它接受一个 Shape 接口的实例作为参数。这看起来很不错,但是,如果我们想要添加一个新的形状,比如椭圆,我们不得不修改 Shape 接口,因为椭圆既不是圆形也不是矩形。这就违反了里氏代换原则,因为基类 Shape 应该能够被其子类的任何实例所替换。

3.2 案例二:符合里氏代换原则的代码

为了修复上一个案例中的问题,我们可以重新设计 Shape 接口和相关的类。这次,我们会使用里氏代换原则来指导我们的设计。

public interface Shape {
    double getArea();
}

public abstract class AbstractShape implements Shape {
    // 抽象方法,由子类实现
    @Override
    public abstract double getArea();
}

public class Circle extends AbstractShape {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }
}

public class Rectangle extends AbstractShape {
    private double width;
    private double height;

    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public double getArea() {
        return width * height;
    }
}

// 新增的椭圆类
public class Ellipse extends AbstractShape {
    private double majorRadius;
    private double minorRadius;

    public Ellipse(double majorRadius, double minorRadius) {
        this.majorRadius = majorRadius;
        this.minorRadius = minorRadius;
    }

    @Override
    public double getArea() {
        return Math.PI * majorRadius * minorRadius;
    }
}

public class ShapeOperations {
    public void draw(Shape shape) {
        System.out.println("Drawing " + shape.getClass().getSimpleName());
    }
}

public class Main {
    public static void main(String[] args) {
        ShapeOperations operations = new ShapeOperations();
        Circle circle = new Circle(5);
        Rectangle rectangle = new Rectangle(4, 5);
        Ellipse ellipse = new Ellipse(3, 2);

        operations.draw(circle);
        operations.draw(rectangle);
        operations.draw(ellipse);
    }
}

在这个改进的例子中,我们创建了一个抽象类 AbstractShape,它实现了 Shape 接口并提供了 getArea 方法的抽象实现。这样,当我们想要添加一个新的形状时,我们只需要创建一个新的子类来实现 AbstractShape 类,而不需要修改现有的 Shape 接口。这符合里氏代换原则,因为 ShapeOperations 类可以接受任何 AbstractShape 的子类实例,而不会影响现有的代码。

3.3 案例对比与分析

通过对比两个案例,我们可以清楚地看到里氏代换原则的重要性。在第一个案例中,由于违反了里氏代换原则,我们无法在不修改 Shape 接口的情况下添加新的形状。而在第二个案例中,由于遵循了里氏代换原则,我们能够轻松地添加新的形状,而不影响现有的类和代码。

四、里氏代换原则在实际项目中的应用

4.1 重构现有代码

在实际的软件开发过程中,我们经常会遇到需要重构代码的情况。重构的目的是提高代码的质量,使其更加清晰、简洁和可维护。里氏代换原则在这个过程中起着重要的作用。以下是一个重构的例子:

假设我们有一个 Animal 类,它有两个子类 DogCat。现在我们想要给 Animal 类添加一个新的方法 makeSound。但是,由于 DogCat 类都有不同的叫声,直接在 Animal 类中添加 makeSound 方法会导致代码的不一致性。这时,我们可以利用里氏代换原则来重构代码。

public interface Animal {
    // 接口中只定义方法,不具体实现
}

public class Dog implements Animal {
    // Dog 类实现 Animal 接口
}

public class Cat implements Animal {
    // Cat 类实现 Animal 接口
}

// 重构后的 Animal 类
public abstract class AbstractAnimal implements Animal {
    // 抽象方法,由子类实现
}

public class Dog extends AbstractAnimal {
    @Override
    public void makeSound() {
        System.out.println("Woof woof");
    }
}

public class Cat extends AbstractAnimal {
    @Override
    public void makeSound() {
        System.out.println("Meow meow");
    }
}

通过重构,我们创建了一个抽象的 AbstractAnimal 类,它实现了 Animal 接口并提供了 makeSound 方法的抽象实现。这样,我们就能够在不修改 DogCat 类的情况下,给 Animal 类添加一个新的方法。这符合里氏代换原则,因为 DogCat 类都能够替换 Animal 类,而不会影响现有的代码。

4.2 设计新的类和方法

在设计新的类和方法时,遵循里氏代换原则是非常重要的。它能够帮助我们创建出更加灵活和可扩展的代码结构。以下是一个遵循里氏代换原则设计新的类和方法的例子:

public interface Payment {
    double calculateAmount(double price);
}

public class CashPayment implements Payment {
    @Override
    public double calculateAmount(double price) {
        return price;
    }
}

public class CreditCardPayment implements Payment {
    @Override
    public double calculateAmount(double price) {
        // 假设信用卡支付需要额外收取 5% 的费用
        return price * 1.05;
    }
}

// 可以使用 Payment 接口来处理不同的支付方式
public class Order {
    private List<Payment> payments = new ArrayList<>();

    public void addPayment(Payment payment) {
        payments.add(payment);
    }

    public double getTotalAmount() {
        double total = 0;
        for (Payment payment : payments) {
            total += payment.calculateAmount(total);
        }
        return total;
    }
}

在这个例子中,我们定义了一个 Payment 接口,它有一个 calculateAmount 方法。然后,我们创建了两个实现 Payment 接口的类:CashPaymentCreditCardPayment。这样,我们就可以使用 Payment 接口来处理不同的支付方式,而不需要修改 Order 类的代码。这符合里氏代换原则,因为 CashPaymentCreditCardPayment 类都能够替换 Payment 类,而不会影响现有的代码。

4.3 测试与验证

在软件开发过程中,测试是非常重要的一个环节。里氏代换原则可以帮助我们编写更加可靠和易于测试的代码。以下是一个使用里氏代换原则进行测试的例子:

public class PaymentTest {
    @Test
    public void testOrderTotalWithCashPayment() {
        Order order = new Order();
        order.addPayment(new CashPayment());
        order.addPayment(new CashPayment());
        double total = order.getTotalAmount();
        Assert.assertEquals(200, total);
    }

    @Test
    public void testOrderTotalWithCreditCardPayment() {
        Order order = new Order();
        order.addPayment(new CreditCardPayment());
        order.addPayment(new CreditCardPayment());
        double total = order.getTotalAmount();
        Assert.assertEquals(210, total);
    }
}

在这个例子中,我们使用了 JUnit 测试框架来编写测试用例。我们分别测试了使用现金支付和信用卡支付的情况下,订单的总金额是否正确。由于我们遵循了里氏代换原则,我们可以使用 Payment 接口来测试不同的支付方式,而不会影响测试的可靠性。

五、里氏代换原则的灵活运用

5.1 应对复杂场景

在实际项目中,我们经常会遇到复杂的场景,这时候里氏代换原则的灵活运用就显得尤为重要。以下是一个应对复杂场景的例子:

假设我们有一个 Person 类,它有两个子类 EmployeeStudent。现在我们想要创建一个 Payroll 类,用于处理员工的工资计算。但是,我们很快发现,Employee 类和 Student 类在工资计算方面有很大的不同,直接使用 Person 类作为基类会导致代码的复杂性和不灵活性。

public interface Person {
    // 定义公共属性
    String getName();
}

public class Employee implements Person {
    private double salary;

    public Employee(double salary) {
        this.salary = salary;
    }

    @Override
    public String getName() {
        // 获取员工姓名
    }
}

public class Student implements Person {
    private String name;

    public Student(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        // 获取学生姓名
    }
}

public class Payroll {
    private Person person;

    public Payroll(Person person) {
        this.person = person;
    }

    public double calculatePay() {
        return person.getName().equals("Employee") ? person.getSalary() : 0;
    }
}

在这个例子中,我们直接使用 Person 类作为基类,导致 Payroll 类中的 calculatePay 方法需要根据传入的 Person 对象来判断是 Employee 还是 Student,从而计算工资。这样,如果将来添加新的子类,比如 Teacher,我们不得不修改 Payroll 类的代码。

为了解决这个问题,我们可以将 Person 类改为一个抽象类,并提供一个 getPayAmount 抽象方法,让子类实现自己的工资计算逻辑。这样,Payroll 类就不需要关心具体的工资计算逻辑,从而更加灵活和可扩展。

public abstract class AbstractPerson implements Person {
    // 定义公共属性
    @Override
    public abstract double getPayAmount();
}

public class Employee extends AbstractPerson {
    private double salary;

    public Employee(double salary) {
        this.salary = salary;
    }

    @Override
    public String getName() {
        // 获取员工姓名
    }

    @Override
    public double getPayAmount() {
        return salary;
    }
}

public class Student extends AbstractPerson {
    private String name;

    public Student(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        // 获取学生姓名
    }

    @Override
    public double getPayAmount() {
        return 0; // 学生没有工资
    }
}

public class Payroll {
    private Person person;

    public Payroll(Person person) {
        this.person = person;
    }

    public double calculatePay() {
        return person.getPayAmount();
    }
}

通过将 Person 类改为一个抽象类,并提供一个 getPayAmount 抽象方法,我们使得 Payroll 类更加灵活和可扩展。这样,无论将来添加什么新的子类,Payroll 类都可以正确地处理工资计算。

5.2 与其他设计原则的配合

里氏代换原则是面向对象设计中的一个基本原则,但它并不是孤立存在的。它需要与其他设计原则相互配合,才能发挥出最大的效果。以下是一个与其他设计原则配合使用的例子:

public interface Animal {
    void makeSound();
}

public class Dog implements Animal {
    @Override
    public void makeSound() {
        System.out.println("Woof woof");
    }
}

public class Cat implements Animal {
    @Override
    public void makeSound() {
        System.out.println("Meow meow");
    }
}

public class AnimalSound {
    private Animal animal;

    public AnimalSound(Animal animal) {
        this.animal = animal;
    }

    public void playSound() {
        if (animal instanceof Dog) {
            ((Dog) animal).makeSound();
        } else if (animal instanceof Cat) {
            ((Cat) animal).makeSound();
        }
    }
}

在这个例子中,我们使用里氏代换原则创建了 Animal 接口和两个实现该接口的类:DogCat。然后,我们使用单一职责原则创建了一个 AnimalSound 类,它有一个 playSound 方法,用于播放不同动物的叫声。这样,我们通过遵循里氏代换原则和其他设计原则,创建了一个更加灵活和可维护的代码结构。

5.3 里氏代换原则的局限性

在这里插入图片描述

虽然里氏代换原则是面向对象设计中的一个重要原则,但它并不是万能的。在某些情况下,它可能会带来一些限制和局限性。以下是一些里氏代换原则的局限性:

  • 接口泛滥:如果一个类有太多的接口,那么可能会导致接口泛滥,使代码变得复杂和不清晰。在这种情况下,可以考虑使用多重继承或者组合的方式来解决这个问题。
  • 子类职责过重:如果一个子类承担了过多的职责,那么可能会导致子类变得过于复杂,难以维护和扩展。在这种情况下,可以考虑将子类的职责拆分成更小的类,或者使用组合的方式来实现。
  • 动态类型安全:在某些情况下,如Java虚拟机(JVM)中,编译器可能无法完全检查出违反里氏代换原则的代码。在这种情况下,需要通过代码审查和测试来确保代码的质量和正确性。

六、总结

6.1 里氏代换原则的核心价值

里氏代换原则是面向对象设计中的一个核心原则,它强调了继承复用性的重要性。通过遵循里氏代换原则,我们可以创建出更加灵活和可扩展的代码结构,使得代码更加易于维护和扩展。它鼓励我们在设计类时,关注类的抽象和通用性,而不是具体的实现细节。这样,当我们需要对类进行扩展时,就可以通过创建新的子类来完成,而不是直接修改基类。这有助于减少代码的耦合度,提高代码的可维护性和可扩展性。

6.2 面向对象设计的重要性

面向对象设计是现代软件开发中的一项基本技能。它不仅可以帮助我们创建出更加灵活和可维护的代码结构,还能够提高我们的编程效率和代码质量。面向对象设计的核心是封装、继承和多态,它们共同构成了面向对象编程的基础。通过使用这些概念,我们可以创建出更加模块化、可重用和易于测试的代码。

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

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

相关文章

CSS——动画(animation)

一、过渡&#xff08;transition&#xff09; 1、通过过渡可以指定一个属性发生变化时的切换方式 2、通过过渡可以创建一些非常好的效果&#xff0c;提升用户体验 3、常用属性值 ① transition-property 指定要执行过渡的属性 多个属性间使用&#xff0c;隔开如果所有…

Ubuntu24.04搭建maxkb开发环境

接上文&#xff1a;windows10搭建maxkb开发环境&#xff08;劝退指南&#xff09; 上文在windows10环境搭建maxkb开发环境遇到各种坑&#xff0c;后面就转战ubuntu平台&#xff0c;果然比较顺利的完成开发环境搭建。当然遇到相关的问题还是可以参考上文《windows10搭建maxkb开发…

数据库根据日期统计SQL编写记录

统计每天产生多少数据 SELECT to_char("日期字段",YYYY-MM-dd) time ,count(*) FROM "表名" GROUP BY time;统计每月产生多少数据 SELECT to_char("日期字段",YYYY-MM) time ,count(*) FROM "表名" GROUP BY time;统计每年产生多少数…

unity游戏开发005:资源的导入

“君子之学&#xff0c;无时无处而不以立志为事” unity游戏开发 前言文章有误敬请斧正 不胜感恩&#xff01;||unity游戏开发005 Unity资源导入指南一、资源的种类二、资源导入的基本步骤三、导入资源的设置四、导入资源的注意事项五、常见问题及解决方案六、总结 前言 昨天我…

大数据技术——实战项目:广告数仓(第八部分)FineBI实战

目录 第1章 FineBI概述 第2章 FineBI部署 第3章 FineBI实战 3.1 需求回顾 3.2 添加Clickhouse驱动 3.3 添加Clickhouse数据库连接 3.4 添加数据集 3.5 创建分析主题并选择数据集 3.6 加工数据 3.7 创建可视化组件 3.7.1 地图可视化组件 3.7.2 投放平台流量柱状图…

【C语言篇】深入理解指针4(模拟实现qsort函数)

文章目录 回调函数是什么qsort函数介绍和使用举例qsort函数介绍qsort函数排序整型数据使用qsort排序结构数据 qsort函数的模拟实现总结写在最后 回调函数是什么 回调函数就是⼀个通过函数指针调⽤的函数。 如果你把函数的指针&#xff08;地址&#xff09;作为参数传递给另⼀…

豆包MarsCode:开启AI辅助编程的新时代

文章目录 引言MarsCode简介主要功能安装步骤JetBrains 安装1. /doc 文档生成2. /fix 智能修复 AI Fix3. /test 单元测试生成 使用步骤深入与最佳实践常见问题解答结语学习资源互动环节 引言 在人工智能技术飞速发展的今天&#xff0c;编程领域的创新也在不断涌现。豆包MarsCod…

从繁琐到高效:采购合同管理软件如何使企业受益

企业普遍面临由合同管理复杂性引发的压力&#xff0c;这已成为一个普遍现象。手动处理和整理大量的关键信息&#xff0c;同时确保所有文档的透明度和一致性&#xff0c;无疑是一项重大挑战。为了降低流程时间并提高效率&#xff0c;采用有效的工具显得尤为必要。 然而&#xf…

44.【C语言】指针(重难点)(G)

目录 19.字符指针变量 *定义 *简单说明 *如果是字符串 *像数组一样指定访问常量字符串的字符 *练习 20.数组指针变量 *定义 *格式 *例子 问题1 问题2 *利用指针打印 21.二维数组传参的本质 往期推荐 19.字符指针变量 *定义 指向字符的指针变量&#xff0c;用于存储字符在内存…

传统软件开发和敏捷软件开发之间的区别

传统软件开发与敏捷软件开发都是系统软件设计开发的方式&#xff0c;都是软件设计的重要类型。 1. 传统软件开发 1.1 基本流程 传统软件开发是用于设计和开发简单软件的软件开发过程。当软件的安全性和许多其他因素不太重要时使用它。它由新手用来开发软件。它包括五个阶段&…

掌控库存,简化管理 — InvenTree 开源库存管理系统

InvenTree &#xff1a;简化您的库存管理&#xff0c;让效率和控制力触手可及。- 精选真开源&#xff0c;释放新价值。 概览 InvenTree&#xff0c;一款专为精细化库存管理而设计的开源系统&#xff0c;以其高效和灵活性在众多库存管理工具中脱颖而出。它以Python和Django框架…

详谈平衡二叉搜索树(AVL树)

文章目录 AVL树的概念AVL树节点AVL树的插入AVL树的旋转新节点插入较高左子树的左侧---左左&#xff1a;右单旋新节点插入较高右子树的右侧---右右&#xff1a;左单旋新节点插入较高左子树的右侧---左右&#xff1a;先左单旋再右单旋新节点插入较高右子树的左侧---右左&#xff…

Vue - 详情介绍v-emoji-picker、vue3-emoji-picker和vue3-emoji表情包组件

Vue - 详情介绍v-emoji-picker、vue3-emoji-picker和vue3-emoji表情包组件 本篇详情介绍在Vue2.x和Vue3.x中使用&#xff08;emoji&#xff09;表情包组件&#xff0c;通过提供直观、易于使用的emoji表情选择功能&#xff0c;增强用户在使用Web应用时的表达力和互动性。 1. v…

Linux驱动开发基础(总线驱动设备模型)

所学来自百问网 目录 1.驱动设计的思想&#xff1a;面向对象/分层/分离 1.1 面向对象 1.2 分层 1.3 分离 2.总线驱动设备模型 2.1 相关函数和结构体 2.1.1 platform_device 2.1.2 platform_driver 2.1.3 相关函数 2.2 platfrom_driver和platfrom_device的注册过程 …

解决麒麟 V10 SP1 升级 Python 后 Yum 不可用问题

目录 一、前提概要 二、解决办法 1、卸载原有的 python 2、安装 Python 3.7.9 rpm 3、安装一系列 yum 相关 rpm 4、rpm 包下载 一、前提概要 在部署 gaussDB 的时候&#xff0c;安装代理时要求 python 版本满足 3.7.9&#xff0c;但已安装的麒麟 V10 内集成的 python 版…

GitHub Actions 遭利用,14个热门开源项目令牌泄露风险激增

近日&#xff0c;有攻击者通过 CI/CD 工作流中的 GitHub Actions 工具窃取了谷歌、微软、AWS 和 Red Hat 等多个知名开源项目的 GitHub 身份验证令牌。 窃取这些令牌的攻击者可在未经授权的情况下访问私有存储库、窃取源代码或向项目中注入恶意代码。 Palo Alto Networks Un…

【STM32 Blue Pill编程】-STM32CubeIDE开发环境搭建与点亮LED

开发环境搭建与点亮LED 文章目录 开发环境搭建与点亮LED1、STM32F103C8T6及STM32 Blue Pill 介绍2、下载并安装STM32CubeIDE3、编程并点亮LED3.1 在Stm32CubeIDE中编写第一个STM32程序3.1.1 创建项目3.1.2 设备配置3.1.2.1 系统时钟配置3.1.2.2 系统调试配置3.1.2.3 GPIO配置3.…

饲料粉碎加工:玉米豆粕小麦秸秆破碎机械设备

饲料粉碎机是一种专门用于将各种原料如玉米、小麦、豆粕、秸秆等物料进行破碎、细化的机械设备。其工作原理主要依赖于旋转的刀盘或锤片&#xff0c;在高速旋转过程中产生强大的冲击力和剪切力&#xff0c;将物料粉碎至所需粒度。这一过程不仅提高了饲料的利用率&#xff0c;还…

鸿蒙环境和模拟器安装

下载华为开发者工具套件&#xff0c;并解压 https://developer.harmonyos.com/deveco-developer-suite/enabling/kit?currentPage1&pageSize10 双击dmg安装ide 复制并解压sdk 安装模拟器 https://yuque.antfin-inc.com/ainan.lsd/cm586u/po19k1mi9b2728da?singleDoc#…

Unity大场景切换进行异步加载时,如何设计加载进度条,并配置滑动条按照的曲线给定的速率滑动

一、异步加载场景的过程 1、异步加载场景用到的API LoadSceneAsync 2、异步加载的参数说明 &#xff08;1&#xff09;默认参数&#xff1a;SceneManagement.LoadSceneAsync(“SceneName”); AsyncOperation task SceneManager.LoadSceneAsync("SceneName");&a…