首页 > 其他分享 >设计原则 (3) 里氏替换原则

设计原则 (3) 里氏替换原则

时间:2024-02-29 16:33:28浏览次数:30  
标签:原则 里氏 替换 子类 父类 public

简介

里氏替换原则(Liskov Substitution Principle,LSP)是面向对象设计中的一个重要原则,由芭芭拉·利斯科夫(Barbara Liskov)在1987年提出。它是继承原则的一种深化和发展,强调子类必须能够替换掉父类并且不影响程序的正确性。

里氏替换原则的定义为:“如果对每一个类型为 S 的对象 o1,都有类型为 T 的对象 o2,使得以 T 定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 S 是类型 T 的子类型。”简单来说,子类型必须能够替换掉父类型,并且程序的行为不能因此而受影响。

里氏替换原则的核心思想是:在使用继承时,子类应该保持父类的行为,即子类对象应该能够替换父类对象并且不产生意外的行为。这样才能确保代码的正确性、可靠性和可扩展性。

具体来说,里氏替换原则包括以下几点:

  1. 子类必须保持父类的接口规范。

  2. 子类可以实现父类的抽象方法,但不应该覆盖父类的非抽象方法。

  3. 子类可以拓展父类的功能,但不能改变父类原有的行为。

  4. 子类在实现父类的方法时,可以引入新的异常,但不能抛出父类方法中未声明的异常。

里氏替换原则的应用可以提高代码的可维护性、可扩展性和可复用性,同时减少系统中的错误和意外行为。它有助于设计出符合面向对象设计原则的良好设计,并且能够使继承关系更加稳定和可靠。

案例

让我们来考虑一个更具体的例子,比如使用形状(Shape)类及其子类矩形(Rectangle)和正方形(Square)来说明里氏替换原则。

using System;

// 定义形状类
public class Shape
{
    // 计算面积的方法
    public virtual double Area()
    {
        return 0;
    }
}

// 定义矩形类,继承自形状类
public class Rectangle : Shape
{
    public double Width { get; set; }
    public double Height { get; set; }

    // 重写计算面积的方法
    public override double Area()
    {
        return Width * Height;
    }
}

// 定义正方形类,继承自矩形类
public class Square : Rectangle
{
    // 重写属性,确保宽和高相等
    public new double Width
    {
        set { base.Width = base.Height = value; }
    }

    // 重写属性,确保宽和高相等
    public new double Height
    {
        set { base.Width = base.Height = value; }
    }
}

class Program
{
    // 接受形状对象作为参数,并输出其面积
    static void PrintArea(Shape shape)
    {
        Console.WriteLine("Area: " + shape.Area());
    }

    static void Main(string[] args)
    {
        // 使用矩形类型的对象
        Rectangle rectangle = new Rectangle { Width = 5, Height = 4 };
        PrintArea(rectangle); // 输出: Area: 20

        // 使用正方形类型的对象
        Square square = new Square { Width = 5 }; // 此时只需设置一个属性即可
        PrintArea(square); // 输出: Area: 25
    }
}

在这个例子中,我们有一个基类Shape,它有一个虚方法Area()用于计算面积。然后有两个子类,Rectangle(矩形)和Square(正方形),分别重写了这个方法。

Main()方法中,我们创建了一个矩形对象和一个正方形对象,然后将它们传递给PrintArea()方法。根据里氏替换原则,我们可以用Square对象替换Rectangle对象,程序的行为不会发生改变。

优点

  1. 代码重用性增强:通过继承和多态,可以更好地重用基类的代码,子类可以继承父类的行为,同时可以在不修改父类的情况下扩展或者修改子类的行为。

  2. 可扩展性增强:当需要新增功能时,可以通过添加新的子类来扩展系统的功能,而不需要修改已有的代码。这样做不会影响现有功能的稳定性。

  3. 灵活性增强:里氏替换原则可以使得系统更加灵活,可以在运行时动态地替换父类对象为其子类对象,从而实现不同的行为。

  4. 降低耦合性:子类可以替换父类而不影响系统的其他部分,这降低了代码的耦合性,提高了系统的可维护性和可拓展性。

缺点

  1. 潜在的破坏性:如果子类不正确地重写了父类的方法,或者增加了自己的行为,可能会导致意外的结果,破坏了程序的正常逻辑,从而违反了里氏替换原则。

  2. 设计复杂性增加:为了满足里氏替换原则,需要对系统的设计进行良好的抽象和分层,这可能会增加设计的复杂性和理解的难度。

  3. 过度继承:过度使用继承可能会导致类的层次结构过于庞大复杂,增加了系统的维护成本和理解难度。

标签:原则,里氏,替换,子类,父类,public
From: https://www.cnblogs.com/mchao/p/18044676

相关文章

  • java 替换Map中key的值
    importjava.util.*;importjava.util.stream.Collectors;publicclassMapKeyReplacement{publicstaticvoidmain(String[]args){//假设我们有如下的List<Map<String,String>>List<Map<String,String>>list=Arrays.asL......
  • 代码随想录算法训练营day08 | leetcode 344. 反转字符串、541. 反转字符串 II、54. 替
    目录题目链接:344.反转字符串-简单题目链接:541.反转字符串II-简单题目链接:[54.替换数字](题目页面(kamacoder.com))题目链接:151.反转字符串中的单词-中等题目链接:[55.右旋字符串](题目页面(kamacoder.com))题目链接:344.反转字符串-简单题目描述:编写一个函数,其作用是将......
  • 适配http分发Directory.Build.props文件,需要替换默认的微软sdk:8.0映像
    背景我们是把Directory.Build.props及其Import的文件,都放在http://dev.amihome.cn那么dockerbuild的时候,也是需要下载Directory.Build.props及其Import的文件的。为了统一这个操作,减少到处写下载脚本的工作,我们把这个下载的脚本,放在映像里。所以我们以mcr.microsoft.com/dotn......
  • 迪米特原则(设计默斯和)
    定义 高内聚低耦合是一个非常重要的设计思想,能够很好的提高代码的可读性和可维护性,缩小功能改动导致导致代码改动范围,实际上,在前面的章节中,我们已经多次提到了这个设计思想。很多设计原则都是以代码的高内聚低耦合为目的的,比如单一原则,基于接口而非编程实现实际上,高内部松耦合,......
  • Spring Boot使用BESApplicationServer宝兰德替换内嵌Tomcat
    移除自带tomcat<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>${spring.version}</version>......
  • KISS 原则 (设计模式)
    KISS定义kiss原则的英文描述又几个版本,计较下边的这几个keepitsimpleandstupid.keepitshortandsimplekeepitsimpleandstraightforward不过仔细看你会发现,他们表达的意思其实差不多,尽量保持简单。它是一个万金油的设计原则,可以在很多场景中,它不仅仅经常用来指......
  • 接口隔离原则(设计模式)
    定义“Clientsshouldnotbeforcedtodependuponinterfacesthattheydonotuse”个人认为接口隔离原则,和单一原则有点像。一个接口实现一个功能。 不过,你应该已经发现,接口隔离原则跟单一职责原则有点类似,不过稍微还是有点区别。单一职责原则针对的是模块、类、接口......
  • 里斯替换原则 (设计模式)
    定义IfSisasubtypeofT,thenobjectsoftypeTmaybereplacedwithobjectsoftypeS,withoutbreakingtheprogram。Functionsthatusepointersofreferencestobaseclassesmustbeabletouseobjectsofderivedclasseswithoutknowingit。子类能够替......
  • ImageList1控件的使用原则
    ImageList1的功能是设计时候,保存好一系列的图片。在设计加载后,绑定好使用控件,这里我们以TrayIcon1控件为例子 要更改 TrayIcon1控件的图标属性,  不能通过修改ImageList1,  要通过更改 TrayIcon1控件的相关属性,     TrayIcon1.IconIndex:=1;Imag......
  • emoji字符的范围、正则替换Emoji字符
    Emoji与Unicode、UTF8Emoji是一种特殊的字符,而不是像QQ表情一样的普通字符的转义表示。在Unicode编码中,占用了U+1F300到U+1F64F中的部分范围。Emoji字符的特殊之处在于,其使用的Unicode字符超出了通常使用的三字节UTF-8编码的Unicode范围,即BMP范围U+0000到U+FFFF。按照UTF-8编码......