liskov 替换原则违反

nit*_*.kk 4 oop liskov-substitution-principle solid-principles

我在学习liskov substitution principle。它说sub classes should be proper replacement for the base classes

我读了一个例子,我在互联网的不同地方找到了这个例子。一类Rectangle.javaheight, width他们setter and getter methods。一个Square.java只需要一个属性的类,即length. 如果我们有,Square.java extending Rectangle.java那么这违反了这一原则。这是因为Rectangle.java期望的用户width只要height修改就不会受到影响,反之亦然。

我的疑惑:

  1. 我们看到的情况是,方法只是用空的打开和关闭大括号覆盖,以防止执行在基类中编写的默认代码。这种情况是否违反了这一原则?

  2. 这个原则也说不inheritance应该仅仅用于重用代码。在下面的情况下,这是一种不好的做法,这是否违反了这一原则?

如果类 Window.java 可从某个图形库获得。假设它具有绘制窗口所需的所有代码。还假设它在使用和绘制时有一个工具栏。如果要求是创建一个没有工具栏的窗口。

简单地创建一个 WindowWithoutToolBar.java 扩展 Window.java 并覆盖 drawToolBarMethod() 并将其留空就可以解决目的。 [可能只是创建工具栏而不是绘制它,以避免其他方法尝试访问工具栏时发生任何异常object] 这是一种不好的做法吗?

创建一个没有工具栏的全新 Window 类将需要重写所有已经在 Window.java 中编写的代码。

  1. 对于数字,如果我们有一个 Integer.java 类,其中包含用于各种算术运算的代码,这些算术运算可以使用整数进行平方等。如果我们以后需要 NaturalNumber.java,我们可以轻松地从现有的 Integer 扩展它。 java 并添加检查以仅将正整数作为输入。

现在如果我们需要 AbsoluteNumber.java 那么如果我们从 Integer.java 扩展它,这是否违反了这个原则(如果 Integer.java 有一些方法如 getValueAfterMultiplyByNegativeOne())?

请提供您的宝贵意见。

问候,

克里希纳·库马尔

Cù *_*iếu 5

有一个检查清单来确定您是否违反了 Liskov。

  • 如果您违反以下其中一项 -> 您违反了 Liskov。
  • 如果你不违反任何 -> 不能得出任何结论。

检查清单:

  • 派生类中不应抛出新异常:如果您的基类抛出 ArgumentNullException,那么您的子类只能抛出 ArgumentNullException 类型的异常或从 ArgumentNullException 派生的任何异常。抛出 IndexOutOfRangeException 违反了 Liskov。
  • 前提条件无法加强:假设您的基类与成员 int 一起使用。现在您的子类型要求 int 为正数。这是增强的先决条件,现在任何在负整数之前运行良好的代码都被破坏了。
  • 不能削弱后置条件:假设您的基类要求在方法返回之前关闭与数据库的所有连接。在您的子类中,您覆盖了该方法并保持连接打开以供进一步重用。您已经削弱了该方法的后置条件。
  • 必须保留不变量:要实现的最困难和最痛苦的约束。不变量在一段时间内隐藏在基类中,揭示它们的唯一方法是阅读基类的代码。基本上,您必须确保在覆盖方法时,在执行覆盖的方法后,任何不可更改的内容都必须保持不变。我能想到的最好的事情是在基类中强制执行这个不变的约束,但这并不容易。
  • 历史约束:当覆盖一个方法时,你不能修改基类中不可修改的属性。看看这些代码,你可以看到 Name 被定义为不可修改(私有集),但 SubType 引入了允许修改它的新方法(通过反射):

    public class SuperType
    {
        public string Name { get; private set; }
        public SuperType(string name, int age)
        {
            Name = name;
            Age = age;
        }
    }
    public class SubType : SuperType
    {
        public void ChangeName(string newName)
        {
            var propertyType = base.GetType().GetProperty("Name").SetValue(this, newName);
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

还有另外两个项目:方法参数的逆变返回类型的协方差。但是在 C# 中是不可能的(我是 C# 开发人员)所以我不关心它们。

参考: