软件构造之关于关于LSP原则的思考与总结

里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。(摘自百度百科)

LSP原则需要满足的一些条件课上已经讲过,这里就不再赘述。下面讲一些我对LSP原则的一些总结与思考:

1.关于pre/post-conditions
        我自己一开始理解有些偏差,单纯的认为preconditions就是我们输入的参数具有的性质,而postconditions是我们返回值或抛出异常需要满足的要求。但是再看了那个“正方形不是长方形”的经典例子后,发现这样的认识是不完善的。

        用哲学的角度去理解。实践的要素有主体、客体和中介,执行一个方法也可以看作一次实践。主体就是我们的ADT实例,客体则是传入的参数,而加工后变为返回值。那么我们的conditions就不仅包含客体的conditions,也包含主体的conditions了。

        回想“正方形不是长方形“的例子,或者看一下这篇。对于SetWidth方法,长方形中执行该方法后,其高度并不会改变,因此后置条件应该是:宽度改变为对应宽度,高度不变。而在正方形中,后置条件时:宽度和高度都设置为对应值。显然,这俩个后置条件是不一样的,在执行完该方法后,实例的状态不能等价,故违反了LSP原则。

        那么怎样才可以满足呢?我的理解是,对于父类型所包含的Rep空间,子类型在执行任何父类型中方法后,所得到的Rep空间应该同父类型执行对应方法所得到的结果是一样的,这样子类型就可以完全当作一个父类型来使用。而正方形的例子显然不满足。

2.关于RI
        关于RI。我们知道RI是对Rep有效值域的约束,在这里我的理解是:父类型RI约束的值域中合法的对象,在子类型中必须有完全的对应,也就是满足从子类型到父类型的一个满射。这样在我们原先使用父类型的情景下,都可以找到一个对应的子类型实例来进行替换了。那么子类型中可以存在父类型RI约束之外的Rep吗?关于这一点我认为是可以的,但是要满足一个前提:postcondition和procondition必须满足要求。这样的话,如果我们单纯使用父类型中的方法的话,得到的Rep值域仍然在父类型的RI约束范围之内,是可以完全替换的;而我们的子类型还可以在更多的场景下使用。

        再回头看正方形、长方形的例子。正方形的Rep只是长方形的一个子集,如果有些场景下必须用到长宽不一致的长方形,那么正方形的实例是不可以替代的,因此不满足LSP。那么长方形可以替代正方形吗?我认为是可以的,只需要在重写正方形中方法时,同步地设置长和宽俩个属性就好了。

3.关于Invariant
        当我们的Rep和各重写的方法满足上面的俩个约束条件后,那么父类型的Invariant也自然能够满足了。

最后,以上是我结合这几天的做题和思考,结合一些查询的资料和老师的讲解,做了一下自己理解的总结。希望大家不吝赐教,指正我的错误。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呆先森HIT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值