我对里氏替换原则的理解是,基类的某些属性或实现的行为,在派生类中也应该保持正确性。
我想这意味着当一个方法在基类中被定义时,在派生类中就不应该被重写,因为用基类代替派生类将会产生不同的结果。我想这也意味着拥有(非纯)虚方法是不好的事情?
我觉得自己可能对这个原则有一些误解。如果没有,我不明白为什么这个原则是好实践。能否有人向我解释一下?谢谢。
我对里氏替换原则的理解是,基类的某些属性或实现的行为,在派生类中也应该保持正确性。
我想这意味着当一个方法在基类中被定义时,在派生类中就不应该被重写,因为用基类代替派生类将会产生不同的结果。我想这也意味着拥有(非纯)虚方法是不好的事情?
我觉得自己可能对这个原则有一些误解。如果没有,我不明白为什么这个原则是好实践。能否有人向我解释一下?谢谢。
里氏替换原则允许子类覆盖基类中的方法。
这可能过于简化,但我记得它是“子类不应该要求更多也不应该承诺更少”。
如果客户端正在使用带有方法something(int i)
的超类ABC
,那么客户端应该能够在没有问题的情况下替换ABC
的任何子类。不要考虑变量类型,可以考虑前置条件和后置条件。
如果我们上面的ABC
基类中的something()
方法具有允许任何整数的放松前提条件,则ABC
的所有子类必须也允许任何整数。例如,子类GreenABC
不允许向something()
方法添加需要参数为正整数的额外前提条件。这将违反里氏替换原则(即要求更多)。因此,如果客户端正在使用子类BlueABC
并向something()
传递负整数,则在需要切换到GreenABC
时客户端不会出错。
相反,如果基类ABC
的something()
方法具有后置条件,例如保证其永远不会返回零值,则所有子类也必须遵守相同的后置条件,否则它们就会违反里氏替换原则(即承诺更少)。
希望这可以帮助理解。
PizzaSharingService
接口或抽象类(基类),有一个share(pizza,numSlices)
方法,它将返回一系列的薄片。前提条件是,numSlices
参数可以是0-12之间的任何数字(包括0),如果数字为0,则会返回一个空列表。于是第一团队创建了一个RoundPizzaSharingService
,将比萨切成三角形的薄片,并遵守有关薄片数量为零的规则。第二个团队创建了一个SquarePizzaSharingService
,但决定如果薄片数量为零,则抛出异常或返回null,这违反了LSP原则。 - dustmachineRectangle
类,它具有setWidth()
和setHeight()
方法。 一个Square
类是Rectangle
的子类,并且覆盖了行为,使得当一个维度被改变时,这个类将保持一个正方形的形状。 如果某人拥有一个对Rectangle
的引用,并调用setWidth(10); setHeight(5);
,那么对于一个矩形而言,它的尺寸应该是10x5,但是如果引用实际上是指向一个Square
,那么尺寸会被修改以使其成为一个正方形。 Square
类是违反LSP原则的一个例子。 - Grundleflecknew Subclass()
的代码提供比Superclass为调用new Superclass()
的代码提供更少的承诺没有问题,因为调用new Subclass()
的代码不能期望收到超类实例。 - supercat有一个流行的例子说,如果它像鸭子一样游泳,嘎嘎地叫,但需要电池,那么它就违反了Liskov替换原则。
简单来说,你有一个基本的Duck类,被某人使用。然后你通过引入PlasticDuck来添加层次结构,其具有与Duck相同的重写行为(如游泳、叫等),但需要电池来模拟这些行为。这实际上意味着你对子类的行为引入了额外的前提条件,要求使用电池来执行之前由基本Duck类无需电池执行的行为。这可能会让Duck类的使用者感到惊讶,并且可能会破坏围绕基本Duck类预期行为构建的功能。
这里是一个好的链接-http://lassala.net/2010/11/04/a-good-example-of-liskov-substitution-principle/
GetHashCode()
,但调用它的客户端(如哈希表)不会知道他们没有调用为Object定义的方法。由于合同仍然得到满足,因此没有违规行为发生。然而,在正方形/矩形示例中,客户端可能能够确定它们被传递的实例的类是什么,或者可能会失败,因此违反了规定。 - quamranaequals必须返回false
,而仅意味着子类必须像其父类一样行事。例如,如果您将超类的成员放入哈希表中作为键,然后使用子类实例进行查找,您将无法找到它,因为在您的情况下它们不相等。 - Vitalii FedorenkoGetHasCode()
或者Shape::GetArea()
,在这些方法中很难检测出错误。比较困难的例子是在正方形和矩形中,为了符合期望,你可能只能让矩形拥有setHeight
和setWidth
方法,而让正方形只拥有setSize
方法。 - quamranaBarbara Liskov, 1987