【问题标题】:Is the Liskov Principle violated if overridden methods return a different value?如果重写的方法返回不同的值,是否违反了 Liskov 原则?
【发布时间】:2015-03-25 09:44:35
【问题描述】:

下面是我的基类,它具有返回“地址一”的 ReturnAddress 方法,并且在子类中我覆盖了返回“地址二”的相同方法。

public class Base     
{         
     public virtual string ReturnAddress()        
     {             
         return "Address one";         
     }    
 }    


public class Derived : Base     
{                  
    public override string ReturnAddress()         
     {             
        return "Address Two";         
     }
}

//Object declaration for base and derived

Base base = new Base();

Derived der = new Derived();

var result = der.ReturnAddress(); // will return "Address Two"
but if we replace der object with base object 

var result = base.ReturnAddress(); //Will return "Address One"

所以子对象不能被父对象替换。

我想知道上面的例子打破了Liskov Principle

【问题讨论】:

  • 你为什么首先使用覆盖方法?这不像你在重用代码..
  • 如果我们用基础对象替换 der 对象是什么意思?
  • 我一直以为是“das object”。
  • Computer Sciences 社区的人可能会为您提供一个很好的答案。
  • @l19:为什么重写必然意味着重用任何代码?

标签: c# oop solid-principles


【解决方案1】:

当您将子对象视为父对象时,LSP 并未声明子对象将始终与父对象执行完全相同的操作。如果是这样的话,从一个对象继承就没有任何意义了。

相反,重点是您可以将Base 对象视为Base 对象或从它派生的任何对象。无论实际对象实例的类型是 Base 还是 Derived,代码都应该工作。现在,如果您的代码在返回 Address Two 时会失败,并且 预计 Address One 会被返回,那么您将破坏 LSP。如果无论返回哪个字符串,您的代码都可以正常工作,那么返回 a 字符串,那么您就完成了 LSP。

LSP 声明您应该能够用另一种类型的对象替换一种类型的对象,“而不改变该程序的任何所需属性”(取自维基百科页面)。这些理想的属性可以是“具有返回字符串的属性”,也可以是“具有返回'地址一'的属性”。您认为该对象的“合意”决定了 LSP 是否被违反。

【讨论】:

  • 严格意义上的LSP涵盖了“行为”。这里的区别是值/结果不同,而不是“行为”。 (我相信OP希望在两者之间划清界限。)
  • 我将 LSP 声明为“派生类必须履行基类的契约”。
  • @user2864740 它声明您应该能够用另一种类型的对象替换一种类型的对象,“而不改变该程序的任何所需属性”(取自维基百科页面)。这些理想的属性可以是“具有返回字符串的属性”,也可以是“具有返回'地址一'的属性”。您认为该对象的“可取性”决定了 LSP 是否适用于此。
  • “desirable”被定义的行为所覆盖,而不是类型系统。
  • @Servy:你的最后一条评论措辞很好,你应该将它添加到你的答案 IMO。
【解决方案2】:

不,不是。

也就是说,除非你改变了地址的含义

例如,如果基础是邮政地址,但派生的是 IP 地址,则为葛底斯堡地址或“adress”的拼写错误。虽然它们有相同的词,所以编译器不会聪明到阻止你,它们是非常不同的词。

换句话说,您并没有在address这个词上玩语言技巧。

【讨论】:

    【解决方案3】:

    读自the description

    • 这些类型是可替换的(它们都是引用类型)。
    • 返回类型没有违反协方差(它们碰巧保持不变)。
    • 输入中没有违反逆变(因为没有输入)。
    • 没有新的异常可以被抛出(两种实现都调用相同的方法)。
    • 没有强化前提条件(在您的特定示例中没有明显的前提条件)。
    • 没有削弱任何后置条件(如上)。
    • 没有修改不变量(因为这两个类恰好都是无状态的)。
    • 没有违反历史规则(因为派生类没有引入可以从基类观察到的可变状态)。

    根据上述,你没有违反 LSP。

    但是,如果您的程序的其余部分有一些我们无法从这两个类中推断出的要求(例如,可能只有一个特定的字符串可以作为这些对象的返回值),那么这些类就没有用了对您而言,无论他们是否尊重或违反 LSP。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-01
      • 2012-01-12
      • 2021-11-17
      • 1970-01-01
      • 2017-07-04
      • 2020-02-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多