博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
OOP的几个原则-----LSP:Liskov替换原则(下)
阅读量:4934 次
发布时间:2019-06-11

本文共 1513 字,大约阅读时间需要 5 分钟。

LSP让我们得出一个结论:一个模型如果孤立的看并不具有真正意义上的有效性.最后那个版本的Square类和Rectangle类是自相容并且有效的,但是从Rectangle类作出合理假设的角度看,这个模型是有问题的.所以模型的有效性只能通过它的客户程序来表现.

那么是什么原因导致Square和Rectangle这个显然合理的模型出现问题?难道Square和Rectangle不存在IS-A的关系吗?对于那些不是g函数的编写者来说,正方形可以是长方形,但是从g函数的角度来说,Square绝不是Rectangle对象,因为Square对象的行为方式和函数g所期望的Rectangle对象的行为方式不相容,从行为方式的角度来看,Square决不是Rectangle.LSP清楚的指出 OOP中的IS-A关系是就行为方式而言,行为方式是可以进行合理的假设,是客户程序所依赖的.

许多时候我们可能会对合理假设的行为方式感到不安,怎样才能知道客户真正的要求呢?有一项技术可以使这些合理的假设明确化,从而支持LSP.它被称为基于契约的设计.

使用契约设计,类的编写者显示地规定针对该类的契约,客户代码的编写者可以通过该契约知道可以依赖的行为.契约是通过为每个方法声明前置条件和后置条件来指定的.要使一个方法执行成功,前置条件必须要为真.执行完毕后,也要保证后置条件为真.

那么设置Rectangle.Width属性的后置条件可看作:width = w && height = old.height

那么派生类的前置条件和后置条件有如下规则:在重新申明派生类的例程中,只能使用相等或者更弱的前置条件来替换原始的前置条件,只能使用相等或更强的后置条件来替换原始的后置条件.

换句话说,当通过基类接口使用对象时,用户只知道基类的前置条件和后置条件.因此派生类的对象不能指望这些用户遵从比基类更强的条件.也就是说它们必须接受基类可以接受的一切.同时派生类必须和基类的所有后置条件一致,也就是说派生类必须完全遵从基类的后置条件,它们的行为方式和输出不能违反基类已经确立的任何限制,基类的用户不应该被派生类的输出扰乱.

有的语言支持前置条件和后置条件,对于C#来说,我们可以使用单元测试和断言来检查这些条件,同时还需要为每个方法的注释中注明它的前置条件和后置条件.

 违反LSP原则的示例通常都是具有迷惑性的.提取公共部分是一个有效的解决办法.如果一组类都支持一个公共的职责,那么它们应该从一个公共的超类继承该职责.

如果公共的超类还不存在,那么就创建一个,并把公共的职责放入其中.毕竟,这样一个类的有用性是确定无疑的----你已经展示了一些类会继承这些职责.而后对系统的扩展也许会加入一个新的子类,该子类可能会以新的方式来支持同样的职责.此时,这个新创建的超类可能会是一个抽象类.

结论:

OCP是OOP中很多说法的核心.如果这个原则应用得有效,应用程序就会具有更强的可维护性,可重用性及健壮性.LSP是使OCP成为可能的主要原则之一.正是子类的可替换性才使得使用基类表示的模块在无需修改的情况下得以扩展.这种可替换性必须是开发人员可以隐式依赖的.这样,如果没有在代码中显示地支持基类型的契约,半额就必须要很好地,广泛地理解这些契约.

术语IS-A的含义过于宽泛以至于不能作为子类型的定义.子类型的正确定义是可替换的,这里的可替换性可以通过显示或者隐式的契约来定义.这样才能使得它们的行为功能和客户程序所期望的保持一致.

转载于:https://www.cnblogs.com/bit64/archive/2012/03/09/2385942.html

你可能感兴趣的文章