违反里氏替换原则

liskov substitution principle violations

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

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

我的疑惑:

  1. 我们看到的情况是,方法只是被空的左括号和右括号覆盖,以防止执行基 class 中编写的默认代码。这样的情况是否违反了这个原则?

  2. 这个原则还说 inheritance 不应该只是为了重用代码。如果出现以下情况,这是一种不好的做法吗?这是否违反了这一原则?

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

Simply Creating a WindowWithoutToolBar.java extending Window.java and overriding the drawToolBarMethod() and leaving it with empty body solves the purpose.[May be just create toolbar and not draw it so as to avoid any exceptions occurring from other methods trying to access toolbar object] Is this a bad practice ?

创建一个没有工具栏的全新 Window class 需要重写所有已经在 Window.java.

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

Now if we need AbsoluteNumber.java then in case we extend it from Integer.java does this violates this principle (in case Integer.java has some method as getValueAfterMultiplyByNegativeOne()) ?

请提供您宝贵的意见。

此致,

克里希纳·库马尔

  1. 我会说这不是违规。如果你抛出像

    这样的异常,我认为这是违规的
    throw new Exception('Not implemented');
    

    当在基础 class / 接口中不期望/记录此异常时。

    这意味着如果你用你的 class 替换现有的 class ,它会抛出异常,其中 base class 没有告诉,并且代码可能会中断,因为有人可能没有实现 try catch围堵.

  2. 继承"should"在大多数情况下不被用来重用代码。组合是要走的路。我会说这是一种不好的做法。只是我的想法。

有趣的问题。

  1. 据我了解,如果将方法留空不会改变该类型的预期行为,这将是 not be 违规行为。基本上,它不仅通过响应 "a Square is a Rectangle",而且它的整个界面产生相同的行为,从而加强了子类型化要求。例如,您提到的设置矩形的宽度不应影响其高度。

  2. 绝对不应该仅将继承用于代码重用。如果它实际上适用于所有可能的子类型,那么继续吧,你可能会没事的。如果它只适用于它们的一个子集,您会发现自己不断地覆盖方法,并在一天结束时编写更多代码。 您可以改为将该通用代码封装到有意义的组件中,然后可以通过组合在您的 classes 中使用这些组件。

  3. 就 Numbers 而言,我认为您偏离了错误的前提。我不会扩展 Integer class 来实现 Naturals。考虑减去两个自然数,其中第二个高于第一个:即。 3 - 5. 在这里,您需要做出选择,要么抛出异常,要么抛出 return 不再是 Natural 的东西。另一种方法是扩展抽象数字 class,您可以在其中定义一组方法,如下所示:

    abstract class Number {
        public abstract Number sum(Number other);
        public abstract Number subtract(Number other);
        public abstract Number multiply(Number other);
        public abstract Number divide(Number other);
    }
    

    此实现并不完美,因为它需要做出一些假设,例如在您对不同类型进行操作时要执行的隐式转换(强制转换)。但在这种情况下,它可以让您更自由地应用 Liskov 替换原则。