设计模式学习:里氏替换原则2016-02-21这节中我们会聊聊里氏替换原则,聊它之前,我们先看看定义。定义:如果对每一个类型为T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。(摘自java与模式一书)如果你觉得定义说的模糊了点,不太清楚,没关系,我们慢慢说明白。里氏替换原则的另一个简短的定义是“所有引用基类的地方必须能透明地使用其子类的对象”。这个可能更清楚点。如果你熟悉的掌握一门面向对象的语言,你应该都可以明白面向对象的继承,子类继承自父类的话,自然的就会继承父类的所有方法(当然前提是父类不要把方法声明为private)。在面向对象中,继承有很多优点:1代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性;2提高代码的重用性;3子类可以形似父类,但又异于父类,“龙生龙,凤生凤,老鼠生来会打洞”是说子拥有父的“种”,“世界上没有两片完全相同的叶子”是指明子与父的不同;4提高代码的可扩展性,实现父类的方法就可以“为所欲为”了,君不见很多开源框架的扩展接口都是通过继承父类来完成的;5提高产品或项目的开放性。而里氏替换原则希望,你在写一个类继承自原有的类的同时,尽量不要去更改原有的方法。话说那么多,最好的方式就是举个例子了。假设你要做一个枪战游戏,我们省去一些其它的细节,我们关注下,人物在开枪的时候的动作,大家应该玩过CF或CS,或者至少听过枪击类游戏。每个人物一般都有一把枪,所以,这里,我们让选手自己持有枪,也就是让枪称为选手的一个属性。请看下面的代码:
例子代码:/* * 虚拟的抢,后面的枪不管如何实现的,都必须保证,shoot这个接口,实现的就是枪的射击,不同的枪的射击方式是不一样的,但是枪的射击理论上有一个共同的步骤 * 就是子弹出来,射向对方,具体如何我们不管,总之,子类在实现枪这个shoot这个射击方法的接口的时候,不能变成是装子弹,这个就违反了里氏替换原则了 * 这里是关键,就是射击的方法还是射击,虽然过程细节不一样,但还是射击 * 如果不明白为什么违反,那么请你再仔细思考下,还是不懂,留言吧。 * */interface Gun{ public void shoot();} //手枪实现Gun接口class HandGun implements Gun{ public void shoot() {System.out.println("手枪射击"); }} //AK47实现Gun接口class AK47 implements Gun{ public void shoot() {System.out.println("AK47射击"); }} //机枪实现Gun接口class MachineGun implements Gun{ public void shoot() {System.out.println("机枪在装子弹");//这里就是违反了里氏替换原则原则 }} class Hero{ String name; Gun gun; public Hero(String name) {this.name=name; } public void setGun(Gun gun) {this.gun=gun; } public Gun getGun(Gun gun) {return gun; } public void shoot() {if(gun==null){ System.out.println("没抢啦,快去拿把枪吧"); return ;}gun.shoot(); }}public class Main{ public static void main(String[] args) {Hero hero=new Hero("神枪手"); //给枪手配上AK47hero.setGun(new AK47());hero.shoot(); //给枪手配上机枪hero.setGun(new MachineGun());hero.shoot();//本来想设计的,结果却变成了装子弹 //这个还是属于比较明显的问题 hero.setGun(new HandGun());hero.shoot(); }}
URL地址:http://www.bianceng.cn/Programming/project/201602/49629.htm