里氏替换原则

定义:

所有引用父类的地方必须能够使用其子类的对象。

 

通俗点:

老爸能干的事情,儿子都能干,反过来儿子能干的事情,老爸未必可以。

 

案例讲解:

大家都打过CS吧,我们来描述下里面用到的枪:

 

枪的主要职责是射击,如何射击在各个具体的子类中定义,手枪是单发射程比较近,步枪威力大射程远,机枪用于扫射。在士兵类中定义类一个方法killEnemy,使用枪来杀敌人,具体使用什么枪来杀敌人,调用的时候才知道。

 

AbstractGun类的源程序代码:

 

手枪,步枪,机枪的实现类:

 

士兵的实现类:

注意:killEnemy方法中用枪杀敌,枪是抽象的,具体使用的枪需要通过setGun方法确定。

 

场景类:

 

有人,有枪,也有场景,运行结果:

士兵开始杀敌……

步枪射击……

 

在这个过程中,我们给三毛这个士兵一把步枪,然后开始杀敌了。如果三毛要使用机枪,当然也可以,直接把sanmao.setGun(new Rifle())修改为sanmao.setGun(new MachineGun())即可,在编写程序Solider士兵类根本就不用知道是那个型号的枪被传入。

 

注意:在类中调用其他类时务必使用父类或接口,如果不能使用父类或接口,则说明类的设计已经违背了LSP原则。

 

我们再来想一想,如果我们有一个玩具枪,该如何定义呢?

 

首先我们想,玩具枪是不能用来射击的,杀不死人的,这个不应该写在shoot方法中。新增加的ToyGun源码:

 

由于引入了新的子类,场景类中也使用了该类,Client稍作修改:

 

运行结果:

士兵开始杀敌人……

坏了,士兵拿着玩具枪来杀敌人,射不出子弹呀!如果在CS游戏中有这种事情发生,那你就等着被人爆头吧,然后看着自己凄惨的倒地。在这种情况下,我们发现业务调用类已经出现类问题,正常的业务逻辑已经不能运行,那该怎么办?

 

好办,两种解决方法:

  1. 在Soldier类中增加instanceof的判断,如果是玩具枪,就不用来杀敌人。这个方法可以解决问题,但是你要知道,在程序中,每增加一个类,所有与这个父类有关系的类都必须修改,你觉的可行么?如果你的产品出现了这个问题,因为修正了这样一个Bug,就要求所有与这个父类有关系的类都增加一个判断,客户非跳起来跟你干架不可!你还想要客户的忠诚于你么?显然,这个方案不行。

  2. ToyGun脱离继承,建立一个独立的类,为了实现代码复用,可以与AbastractGun建立关联委托关系,如图:

    例如:可以在AbastractToy中声明将声音,形状都委托给AbastractGun处理,仿真枪嘛,形状和声音都要和真实的枪一样了,然后两个基类下的子类自由延展,互不影响。

     

注意:如果子类不能完整的实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖,聚集,组合等关系代替继承。

 

子类可以有自己的个性:

还是刚才关于枪的例子,步枪有几个比较响亮的型号,比如:AK47,AUG狙击步枪等,把这两个型号的枪引入后Rifle子类如图:

 

很简单,AUG继承了Rifle类,狙击手(Snipper)则直接使用类AUG狙击步枪,源码如下:

 

有狙击枪就有狙击手,狙击手类的源码:

 

狙击手使用狙击枪来杀死敌人,业务场景Client类的源码:

 

 

狙击手使用G3杀死敌人,运行结果:

通过望远镜查看敌人……

AUG射击……

 

在这里,系统直接调用了子类,狙击手是很依赖枪支的,别说换一个型号的枪了,就是换一个同型号的枪也会影响射击,所以这里就直接把子类传递进来。这时候,我们能不能直接使用父类传递进来呢?

 

修改Client类:

 

显示不行的,会在运行期抛出java.lang.ClassCastException异常,这也是大家经常说的向下转型是不安全的,从里氏替换原则来看,就是有子类出现的地方父类未必就可以出现。

 

写在最后:

希望能通过上面的例子理解此原则,其实这个原则更多的是制定一种规则,在设计继承时,能够按照此原则来设计。

 

大旗不挥,谁敢冲锋-6大设计原则:

单一职责原则

 

 

个人å¬ä¼å·

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值