Ais*_*war 57 liskov-substitution-principle design-principles solid-principles
我对Liskov替换原则的理解是,对于派生类,基类的某些属性是真的或某些实现的基类行为.
我想这意味着当一个方法在基类中定义时,它永远不应该在派生类中被覆盖 - 因为那么替换基类而不是派生类会产生不同的结果.我想这也意味着,拥有(非纯)虚拟方法是件坏事吗?
我想我可能对这个原则有错误的理解.如果我不这样做,我不明白为什么这个原则是好的做法.谁可以给我解释一下这个?谢谢
dus*_*ine 57
Liskov Substituion Principle完全允许基类中的子类重写方法.
这可能会过多地简化它,但我记得它是"一个子类应该只需要更多,并且承诺不会更少"
如果客户端正在ABC使用带有方法的超类something(int i),则客户端应该能够替换任何子类而ABC不会出现问题.而不是根据变量类型来考虑这一点,或许可以根据前提条件和后置条件来考虑它.
如果我们something()在ABC上面的基类中的方法具有允许任何整数的宽松前提条件,那么所有子类也ABC 必须允许任何整数.GreenABC不允许子类向something()需要参数为正整数的方法添加附加前置条件.这将违反Liskov替代原则(即需要更多).因此,如果客户端正在使用子类BlueABC并且将负整数传递给something()客户端,则在我们需要切换时不会中断GreenABC.
相反,如果基ABC类something()方法具有后置条件 - 例如保证它永远不会返回零值 - 那么所有子类也必须遵守相同的后置条件或者它们违反Liskov替换原则(即,承诺更少).
我希望这有帮助.
vib*_*bhu 10
有一个流行的例子说,如果它像鸭子一样游泳,嘎嘎喜欢鸭子,但需要电池,那么它打破了Liskov替代原则.
简单地说,你有一个基础鸭类,正在被某人使用.然后你通过介绍PlasticDuck添加层次结构与鸭子相同的重写行为(如游泳,嘎嘎等),但需要电池来模拟这些行为.这实际上意味着您要为Sub Class的行为引入一个额外的前提条件,要求电池执行与之前没有电池的Base Duck类所做的相同的行为.这可能会让您的Duck类的消费者感到意外,并且可能会破坏围绕Base Duck类的预期行为构建的功能.
这是一个很好的链接 - http://lassala.net/2010/11/04/a-good-example-of-liskov-substitution-principle/
不,它告诉您应该能够以与其基础相同的方式使用派生类.有很多方法可以覆盖方法而不会破坏它.一个简单的例子,C#中的GetHashCode()是所有类的基础,并且它们中的所有类都可以用作"对象"来计算哈希码.据我所知,破坏规则的一个典型例子是从矩形中导出Square,因为Square不能同时具有宽度和高度 - 因为设置一个会改变另一个,因此它不再符合Rectangle规则.但是,您仍然可以使用.GetSize(),因为所有形状都可以执行此操作 - 因此任何派生的形状都可以替换并用作Shape.
如果您更改由基本方法定义的任何行为,则覆盖会破坏 Liskov 替换原则。意思就是:
从这两个要求中,您可以暗示子方法中的任何新功能不影响超级方法的预期内容都不会违反该原则。这些条件允许您在需要超类实例的情况下使用子类实例。
如果不遵守这些规则,一个类就会违反 LSP。一个典型例子是以下的层次结构:类Point(x,y),类ColoredPoint(x,y,color),其延伸Point(x,y)并覆盖的方法equals(obj)中ColoredPoint,它反映颜色平等。现在,如果有一个实例,Set<Point>他可以假设具有相同坐标的两个点在该集合中相等。重写方法不是这种情况equals,一般来说,没有办法在equals不破坏 LSP 的情况下扩展可实例化的类并添加方法中使用的方面。
因此,每次违反此原则时,都会隐含地引入一个潜在的错误,该错误会揭示何时不满足代码预期的父类的不变性。然而,在现实世界中,通常没有不违反 LSP 的明显设计解决方案,因此可以使用例如@ViolatesLSP类注释来警告客户端在多态集合或任何其他类型中使用类实例是不安全的依赖于 Liskov 替换原则的案例。