首页 > 其他分享 >面向对象设计的六大原则(SOLID原则)-——里氏替换原则

面向对象设计的六大原则(SOLID原则)-——里氏替换原则

时间:2024-03-14 18:57:01浏览次数:19  
标签:double 原则 SOLID 里氏 替换 子类 父类 public

里氏替换原则(Liskov Substitution Principle, LSP)是面向对象设计的基本原则之一,由Barbara Liskov提出。它表明,如果程序中的对象使用的是基类型的话,那么无论它实际上使用的是哪一个子类的对象,程序的行为都不会发生改变。简单来说,子类型必须能够替换它们的基类型,而且替换后程序的行为仍然保持正确。

里氏替换原则详细解释

  1. 子类必须完全实现父类的方法:子类不应该改变父类已有方法的预期行为。如果父类中的某个方法在子类中没有被正确地实现(或者说,子类改变了父类方法的预期行为),那么当使用这个子类替换父类时,就可能会导致程序出现错误。

  2. 子类可以增加自己的特有方法:子类可以扩展父类的功能,但这不应该影响父类方法的行为。

  3. 子类返回的类型必须与父类方法返回的类型兼容:如果父类方法声明返回一个类型,那么子类中被覆盖的方法也应该返回相同类型或者其子类型。

  4. 子类不应该抛出比父类方法更多的异常:子类方法抛出的异常应该与父类方法抛出的异常类型相同或者是其子类。

  5. 子类应该尊重父类的约定和前置条件:父类在设计中可能有一些前置条件或者约束,子类在实现时必须遵循这些前置条件和约束。

里氏替换原则的应用场景例子(C#)

场景1:几何图形面积计算

假设有一个基类Shape,它定义了一个计算面积的方法CalculateArea。然后有两个子类CircleRectangle,分别实现了圆形和矩形的面积计算。

public abstract class Shape  
{  
    public abstract double CalculateArea();  
}  
  
public class Circle : Shape  
{  
    public double Radius { get; set; }  
  
    public override double CalculateArea()  
    {  
        return Math.PI * Math.Pow(Radius, 2);  
    }  
}  
  
public class Rectangle : Shape  
{  
    public double Width { get; set; }  
    public double Height { get; set; }  
  
    public override double CalculateArea()  
    {  
        return Width * Height;  
    }  
}  
  
// 使用示例  
Shape shape = new Circle { Radius = 5 };  
double area = shape.CalculateArea(); // 应该是圆的面积  
  
shape = new Rectangle { Width = 4, Height = 6 };  
area = shape.CalculateArea(); // 应该是矩形的面积

在这个例子中,CircleRectangle都能够替换Shape类型,而且计算面积的行为符合预期。

场景2:动物叫声

假设有一个基类Animal,它定义了一个发出叫声的方法MakeSound。然后有两个子类DogCat,分别实现了狗和猫的叫声。

public abstract class Animal  
{  
    public abstract void MakeSound();  
}  
  
public class Dog : Animal  
{  
    public override void MakeSound()  
    {  
        Console.WriteLine("Woof!");  
    }  
}  
  
public class Cat : Animal  
{  
    public override void MakeSound()  
    {  
        Console.WriteLine("Meow!");  
    }  
}  
  
// 使用示例  
Animal animal = new Dog();  
animal.MakeSound(); // 输出 Woof!  
  
animal = new Cat();  
animal.MakeSound(); // 输出 Meow!
 

在这个例子中,DogCat都能够替换Animal类型,并且正确地发出了各自的叫声。

里氏替换原则确保了在面向对象设计中,子类可以安全地替换父类而不会出现意外的行为。它鼓励我们在设计继承关系时,确保子类遵循父类的约定,并且不会对父类的使用者造成意外的副作用。

 

当然,让我们以一个实际的应用场景为例来说明里氏替换原则的应用:一个车辆追踪系统。

在这个系统中,我们有一个基类Vehicle,它定义了所有车辆共有的属性和行为,比如位置、速度以及一个更新位置的方法UpdatePosition。然后,我们有两个子类CarBicycle,分别代表汽车和自行车,它们继承了Vehicle类并实现了自己的特有属性和行为。

public abstract class Vehicle  
{  
    public double Latitude { get; set; }  
    public double Longitude { get; set; }  
    public abstract double Speed { get; }  
  
    public void UpdatePosition(double time)  
    {  
        // 这里简化处理,实际中可能需要更复杂的计算  
        Latitude += Speed * time * Math.Cos(Math.PI / 4); // 假设向北偏东45度方向移动  
        Longitude += Speed * time * Math.Sin(Math.PI / 4); // 假设向北偏东45度方向移动  
    }  
}  
  
public class Car : Vehicle  
{  
    public override double Speed => 80; // 假设汽车的速度是80km/h  
    // Car可能还有其他特有的属性和方法,比如油门、刹车等  
}  
  
public class Bicycle : Vehicle  
{  
    public override double Speed => 15; // 假设自行车的速度是15km/h  
    // Bicycle可能还有其他特有的属性和方法,比如脚踏板、手刹等  
}
 

现在,假设我们的车辆追踪系统有一个方法TrackVehicle,它接受一个Vehicle类型的参数,并更新车辆的位置:

public class VehicleTracker  
{  
    public void TrackVehicle(Vehicle vehicle, double time)  
    {  
        vehicle.UpdatePosition(time);  
        Console.WriteLine($"Vehicle is now at ({vehicle.Latitude}, {vehicle.Longitude})");  
    }  
}
 

由于CarBicycle都是Vehicle的子类,并且它们没有改变UpdatePosition方法的预期行为(即更新车辆的位置),所以我们可以安全地将它们作为参数传递给TrackVehicle方法,而不需要修改该方法的代码:

VehicleTracker tracker = new VehicleTracker();  
Car car = new Car();  
Bicycle bicycle = new Bicycle();  
  
tracker.TrackVehicle(car, 1.0); // 追踪汽车1小时后的位置  
tracker.TrackVehicle(bicycle, 1.0); // 追踪自行车1小时后的位置

这个例子中,CarBicycle子类完全遵循了里氏替换原则:它们扩展了Vehicle父类的功能(通过实现自己的速度和可能的特有方法),但没有改变父类方法的预期行为。因此,我们可以在不修改原有代码的情况下,将子类对象替换为父类对象进行使用,保证了程序的正确性和可扩展性。

里氏替换原则的应用场景非常广泛,在软件开发和设计的很多方面都能体现其重要性。以下是里氏替换原则的一些具体应用场景:

  1. 设计可扩展的软件系统:在设计一个需要不断添加新功能的软件系统时,可以应用里氏替换原则来确保新添加的子类不会破坏现有系统的功能。这有助于构建可扩展且易于维护的软件系统。

  2. 实现多态性:在面向对象编程中,多态性允许使用父类引用来调用子类的方法。里氏替换原则确保了子类可以无缝地替换父类,从而实现多态性,提高代码的灵活性和可复用性。

  3. 设计插件系统:在设计插件系统时,可以应用里氏替换原则来定义插件接口。这样,不同的插件实现可以替换原始插件,而不需要修改主程序的代码。

  4. 数据库访问层设计:在构建数据库访问层时,可以使用里氏替换原则来设计数据访问对象(DAO)。不同的数据库实现可以替换原始数据库实现,而不会对上层业务逻辑产生影响。

  5. 测试驱动开发(TDD):在TDD中,里氏替换原则有助于编写可测试的代码。通过确保子类可以替换父类,可以更容易地编写针对父类的单元测试,并在必要时使用子类进行测试。

  6. 设计模式实现:许多设计模式,如策略模式、工厂模式、观察者模式等,都依赖于里氏替换原则来实现其灵活性和可扩展性。

  7. 软件升级和维护:在软件升级和维护过程中,里氏替换原则有助于确保新版本的代码与旧版本兼容。通过遵循该原则,可以减少因修改或替换类而导致的潜在问题。

  8. 重构现有代码:在重构现有代码时,里氏替换原则可以作为一种指导原则,帮助开发者识别并修复违反该原则的代码。这有助于提高代码的质量和可维护性。

总之,里氏替换原则在软件开发的各个阶段都发挥着重要作用,有助于构建健壮、可扩展且易于维护的软件系统。在实际项目中,开发者应该时刻关注并遵循这一原则,以确保代码的质量和可维护性。

标签:double,原则,SOLID,里氏,替换,子类,父类,public
From: https://www.cnblogs.com/forges/p/18073693

相关文章

  • 复合索引和最左前缀原则
    复合索引复合索引是根据多个列创建的数据库索引。它们对于优化涉及这些列的查询性能非常有用。在创建复合索引时,这些列的顺序至关重要,因为它决定了数据库如何利用该索引。列的顺序确定复合索引中列的顺序时,应考虑以下因素:查询模式:考虑哪些列经常一起出现在WHERE子句中。选择......
  • 面向对象设计的六大原则(SOLID原则)-——开闭原则
    开闭原则(Open-ClosedPrinciple,OCP)是面向对象设计的五大SOLID原则之一。这个原则主张“软件实体(类、模块、函数等)应该对扩展开放,对修改关闭”。也就是说,软件的设计应该允许在不修改原有代码的情况下增加新的功能。这样的设计有助于降低代码的复杂性和维护成本,同时提高系统的可复......
  • 16条前端 UI 设计原则
    以一个卡片为例子,逐一按照规则进行优化,左边是原图,右边是经过优化后的设计。规则使用间距对相关元素进行分组一致性确保功能相似外观也相似清晰的视觉层次移除不必要的样式有目的的使用颜色确保界面元素的对比度为3:1确保文本的对比度为4.5:1不要仅仅使用颜色作为指标......
  • 软件设计原则 详解
    软件设计原则是指在软件开发过程中,为了保证软件系统的质量和可维护性,所制定的一系列指导性准则。这些原则旨在帮助开发人员编写出高质量、可扩展、易维护、可复用的软件代码。以下是一些常见的软件设计原则:单一职责原则(SingleResponsibilityPrinciple,SRP):一个类应该只有一个......
  • 在Docker中,构建镜像应该遵循哪些原则?
    构建Docker镜像时,应当遵循以下一系列最佳实践和原则,以确保镜像的高效、安全和易于维护:镜像最小化:选择尽可能小的基础镜像,如AlpineLinux,或者针对特定场景选择轻量级的基础镜像。只安装应用程序运行所必需的软件包和服务,避免无关组件和文件。在构建过程中清理临时文件和构建......
  • mysql8.0 性能优化配置 innodb_buffer_pool_size(配置原则和方式)
    1. BufferPool缓冲池是主内存中的一个区域,InnoDB在访问表和索引数据时会在该区域进行缓存。缓冲池允许直接从内存访问频繁使用的数据,这加快了处理速度。在专用服务器上,通常会将高达80%的物理内存分配给缓冲池。2.简单优化把innodb_buffer_pool_size设置为1G。专用服务......
  • 使用-solidity-开发第一个-以太坊智能合约
    目录目录使用solidity开发第一个以太坊智能合约前言项目源代码最终效果环境搭建智能合约内容Truffle创建项目Truffle编码Truffle打包Truffle部署修改编译器版本0.8.19Truffle测试创建测试文件运行测试命令Dapp命令总结遇到的问题注意Solidity......
  • SOLIDWORKS参数化设计之工程图更新 慧德敏学
    SOLIDWORKS参数化设计不仅仅包括三维模型的参数化设计,还包括工程图的自动更新,由于自动出图仍然存在一定的局限性,不能完美的实现视图的布局及尺寸的标注,因此,现阶段采用的最多的仍然是图纸的更新,也就是利用SOLIDWORKS本身三维与二维模型的关联性,当三维模型尺寸变化之后,二维图纸随着......
  • 系统科学方法及基本原则
    系统科学方法是一种综合性的科学研究方法,它以系统为基本研究对象,通过运用系统的思维,从整体和全局出发,研究系统的内在复杂性。这种方法强调整体观念和综合观念,认为系统是由其各部分组成的,但整体功能大于各部分功能之和。系统科学方法的特征包括整体性、综合性、科学性、动态性和应......
  • 设计原则&模式:六大设计原则
     单一职责原则(SRP:SingleReposibility Principle)定义:一个类或者模块只负责完成一个职责。 里氏替换原则(LSP:LiskovSubstitutionPrinciple)定义:所有使用父类的地方可以使用子类的对象,子类可以扩展父类的功能,但是不能替换父类的功能。如果需要替换父类功能,建议——多用组合,......