一、定义
所有引用基类的地方,必须能透明的使用其子类对象。通俗的说:遵循里氏替换原则的代码,只要父类出现的地方就可以使用子类来替换它而不会产生任何错误,使用者不需要知道用的是父类还是子类。
它的核心是继承
友情提醒:xmind导出的图片有点模糊,请放大查看
二、优缺点
它的核心是继承,它的优缺点也是继承的优缺点
2.1 优点
2.2 缺点
- 侵入性:继承是具有侵入性的,强制继承父类的属性和方法
- 灵活性:降低了了灵活性,子类必须拥有父类的方法,从子类角度看,子类被父类约束了
- 耦合性:耦合性增强,子类继承了父类的属性和方法,如果修改父类,那么所有子类的逻辑有可能都要修改
三、重点
四、 注意点
五、案例
路边摆摊打气球,我们可以用玩具枪射击,也可以用仿真枪射击。用代码描述出来。
5.1 遵循里氏替换原则代码实现
/** * 枪的抽象类,包含抽象方法和一个成员变量 * * Created by rytong on 2017/11/14. */ public abstract class IGun { protected static final String TAG = "IGun"; public abstract void shoot(); }
玩具枪类,仿真枪类似:
/** * 玩具枪类 * Created by rytong on 2017/11/14. */ public class PlayerGun extends IGun { @Override public void shoot() { Log.e(TAG,"用玩具枪打气球"); } }
打气球的玩家:
/** * 打气球的玩家 * Created by rytong on 2017/11/14. */ public class Player { IGun gun; public Player(IGun gun) { this.gun = gun; } public void shoot(){ gun.shoot(); } }
玩家打气球:
IGun iGun = new PlamingGun(); new Player(iGun).shoot(); IGun iGun1 = new PlayerGun(); new Player(iGun1).shoot();
玩家打了两枪,结果:
11-14 21:04:49.084 20053-20053/com.designpatterndisclipline E/IGun: 使用仿真枪打气球 11-14 21:04:49.084 20053-20053/com.designpatterndisclipline E/IGun: 用玩具枪打气球
5.2 修改逻辑模拟不严格遵循里氏替换原则可能存在的问题
给IGun增加两个方法,一个内部调用,一个开放出来player调用
/** * 枪的抽象类,包含抽象方法和一个成员变量 * * Created by rytong on 2017/11/14. */ public abstract class IGun { protected static final String TAG = "IGun"; public abstract void shoot(); private void preBullet(){ Log.e(TAG,"先准备好子弹才能射击。"); } public void fire(){ preBullet(); shoot(); } }
PlayerGun不遵循里氏替换原则,覆盖父类的成员变量和方法,而PlamingGun完全遵循里氏替换原则。
/** * 玩具枪类 * Created by rytong on 2017/11/14. */ public class PlayerGun extends IGun { private String TAG = "PlayerGun"; @Override public void shoot() { Log.e(TAG,"用玩具枪打气球"); } @Override public void fire() { // super.fire(); Log.e(TAG,"我在玩玩具枪,不打气球"); } } /** * 仿真枪类 * Created by rytong on 2017/11/14. */ public class PlamingGun extends IGun { @Override public void shoot() { Log.e(TAG,"使用仿真枪打气球"); } }
/** * 打气球的玩家 * Created by rytong on 2017/11/14. */ public class Player { IGun gun; public Player(IGun gun) { this.gun = gun; } public void shoot(){ gun.fire(); } }
玩家射击气球:
IGun iGun = new PlamingGun(); new Player(iGun).shoot(); IGun iGun1 = new PlayerGun(); new Player(iGun1).shoot();
执行结果:
11-14 21:17:50.800 28393-28393/com.designpatterndisclipline E/IGun: 先准备好子弹才能射击。 11-14 21:17:50.800 28393-28393/com.designpatterndisclipline E/IGun: 使用仿真枪打气球 11-14 21:17:50.802 28393-28393/com.designpatterndisclipline E/PlayerGun: 我在玩玩具枪,不打气球
如果设计时规定了要遵循里氏替换原则那么就要严格遵守,否则在编程过程中往往会发生一些难以预料的错误,也就是你的代码的bug率会大大提升。