我正在研究liskov substitution principle
。它说sub classes should be proper replacement for the base classes
。
我读了一个我在互联网上不同地方发现的例子。包含Rectangle.java
及其height, width
的班级setter and getter methods
。类Square.java
,只需要一个属性,即length
。如果我们有Square.java extending Rectangle.java
,那么这违反了这一原则。这是因为Rectangle.java
的用户希望width
只有height
被修改才会受到影响,反之亦然。
我的怀疑:
我们看到的情况是用空的open和close括号覆盖方法,以防止执行在基类中编写的默认代码。这种情况是否违反了这一原则?
这个原则还说inheritance
不应仅用于重用代码。如果如下是不好的做法,这违反了这个原则吗?
如果可以从某个图形库获得类Window.java。假设它具有绘制窗口所需的所有代码。还假设它在使用和绘制时有一个工具栏。如果要求是创建一个没有工具栏的窗口。
简单地创建一个WindowWithoutToolBar.java,扩展Window.java和 覆盖drawToolBarMethod()并将其留空 解决了这个目的。[可能只是创建工具栏而不是绘制它以避免尝试访问工具栏对象的其他方法发生任何异常]这是一种不好的做法吗?
创建一个没有工具栏的全新Window类需要重写已经在Window.java中编写的所有代码。
现在如果我们需要AbsoluteNumber.java,那么万一我们扩展它 Integer.java这样做违反了这个原则(如果是Integer.java 有一些方法作为getValueAfterMultiplyByNegativeOne())?
请提供宝贵的意见。
此致
克里希纳库马尔答案 0 :(得分:4)
有一个检查清单,用于确定您是否违反了Liskov。
检查清单:
历史记录约束:覆盖方法时,不允许修改基类中的不可修改属性。看一下这些代码,您可以看到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);
}
}
另外还有2个项目:方法参数的反演方法和返回类型的协方差。但是在C#(我是C#开发人员)中是不可能的,所以我不关心它们。
参考:
答案 1 :(得分:3)
有趣的问题。
据我了解,如果将方法保留为空,则会not be
违规,并不会改变该类型的预期行为。基本上,它不仅响应“一个正方形是一个矩形”,而且它的整个界面产生相同的行为,从而强化了子类型要求。例如,您提到的关于设置矩形宽度的内容不应影响其高度。
绝对继承不应仅用于代码重用。如果它实际上适用于所有可能的子类型,那么继续,你可能会没事的。如果它仅适用于它们的子集,您将发现自己不断重写方法,并在一天结束时编写更多代码。 您可以将该公共代码封装到有意义的组件中,然后通过组合在您的类中使用。
在Numbers的情况下,我认为你正在偏离错误的前提。我不会扩展Integer类来实现Naturals。想一想减去两个自然,其中第二个高于第一个自然:即。 3 - 5.在这里,你需要做出选择,既可以抛出异常,也可以返回不再是自然的东西。另一种方法是扩展抽象的Number类,您可以在其中定义一组方法:
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替换原则。
答案 2 :(得分:2)
我想说这不是违规行为。我认为如果抛出像
这样的异常会违反规定throw new Exception('Not implemented');
在基类/接口中不期望/记录此异常时。
这意味着如果你用你的现有类替换它,它会抛出一个异常,基类没有告诉,代码可能会破坏,因为有人可能没有实现try catch块。
在大多数情况下,不应使用继承“应该”来重用代码。构图是要走的路。我会说这是一个不好的做法。只是我的想法。