原则6-里氏替换原则

我们考虑一个场景,在一款游戏里面,玩家使用枪械射击,由于枪械的种类在不断增加,并且每种枪都在不停的做性能微调,所以基于开放-封闭原则考虑,抽象枪的使用,将枪的种类增加和枪的性能调整进行封装,枪的使用抽象:拾起、装弹、瞄准、射击、丢弃,这个抽象出来的基类可以是抽象类(或接口)也可以是普通的父类都没有问题;玩家client在使用枪的时候直接使用基类操作其指向的具体枪支类就好了;

这里有个问题,我写了一个玩具枪类,理论上它也是枪,于是我继承基础枪类,但是玩具其无法射击,所以,如果基类的射击方法是抽象的,我在实现这个射击函数时直接返回不可射击的错误;如果这个基类的射击方法是非抽象的,我就要在子类中重写这个函数并返回不可射击的错误;

如果真把这个玩具枪加入到程序中,那么client在使用的枪的时候就要先判断这个枪是否为玩具枪,如果是就换一个(不换就等死吧)。这样做就强制修改了client类,违背了开放-封闭原则;而强制的让玩具枪继承自基类枪就违背了里氏替换原则;

 

里氏替换原则:

定义1:如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。

定义2:所有引用基类的地方必须能透明地使用其子类的对象。即,继承要确保父类所拥有的性质在子类中依然存在;

 

里氏替换原则是衡量 继承关系质量 的一个标准,只有当子类替换掉当前正在引用的基类,而软件功能不受影响时(不报错,逻辑思路正常),基类才能真正被复用,这时候再谈论子类的扩展才有意义;

 

实现里氏替换原则的方式:子类可以扩展父类的功能,但不能改变父类原有的功能。

1、对于基类的抽象函数方法,子类要全部实现并确保逻辑思维正确;

2、对于基类的非抽象函数方法,子类不应该重新实现:

a)java,在定义基类的非抽象函数方法时最好加上final,避免子类实现过程中覆盖掉(override)此函数;

b)java,在子类中定义与基类函数名相同但参数不同的函数时,这些函数被认为是重载,此时注意子类函数参数范围要比基类对应函数参数范围要大,子类函数返回值要比基类对应函数返回值范围要小;

c)c++,在子类中定义与基类同名的函数(无 virtual修饰),会对基类同名函数进行隐藏,没办法,c++的这点无法满足LSP原则;

d)注意抽象类中也可以有非抽象函数的呦!

3、如果可以,尽量使用接口或抽象类的方式设计继承关系;

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值