共计 1591 个字符,预计需要花费 4 分钟才能阅读完成。
里氏准则为良好的继承定义了一个标准。
一句简略的定义蕴含了 4 层含意。
1. 子类必须齐全实现父类的办法
咱们举个例子来阐明这个准则,十分经典的游戏 CS,咱们来形容一下外面的枪支。类图如图所示
枪的次要作用是射击,如何射击正各个具体的子类中定义,手枪是单发射程比拟近,步枪威力大射程远,机枪用于扫射。在士兵类外面定义一个办法 killEnemy,应用枪来杀死敌人,具体用什么枪来杀敌人,调用的时候才晓得。
代码清单 枪支的抽象类
package cn.yxnu.pattern_2; | |
// 定义一个形象父类 枪的父类 | |
public abstract class AbstractGun { | |
// 枪用来干什么?杀敌 | |
public abstract void shoot();} |
代码清单 手枪、步枪、机枪的类
package cn.yxnu.pattern_2; | |
// 手枪类 | |
public class HandGun extends AbstractGun{ | |
// 手枪的特点是不便携带,射程短 | |
@Override | |
public void shoot() {System.out.println("手枪射击..."); | |
} | |
} |
package cn.yxnu.pattern_2; | |
// 步枪类 | |
public class Rifle extends AbstractGun{ | |
// 步枪的特点是射程远,威力大 | |
@Override | |
public void shoot() {System.out.println("步枪射击..."); | |
} | |
} |
package cn.yxnu.pattern_2; | |
// 机枪类 | |
public class MachineGun extends AbstractGun{ | |
// 机枪的特点是扫射 | |
@Override | |
public void shoot() {System.out.println("机枪扫射..."); | |
} | |
} |
有了枪支,还要有能应用这些枪支的士兵
代码清单 士兵类
package cn.yxnu.pattern_2; | |
// 士兵类 | |
public class Soldier { | |
// 定义士兵的枪支 | |
private AbstractGun gun; | |
// 给士兵一只枪 | |
public void setGun(AbstractGun abstractGun){this.gun = abstractGun;} | |
// 士兵有杀死敌人的办法 | |
public void killEnemy() {System.out.println("士兵杀敌人..."); | |
// 枪射击 | |
gun.shoot();} | |
} |
士兵应用什么枪来杀敌,然而这把枪是形象的具体是手枪还是步枪还是机枪,须要在上战场前(也就是 Client 中)通过 setGun()办法来确定。
代码清单 场景 Client 类
package cn.yxnu.pattern_2; | |
// 里式替换准则 | |
// 这是一个场景类 | |
public class Client {public static void main(String[] args) { | |
// 生成一个名字叫 三毛 的士兵 | |
Soldier sanMao = new Soldier(); | |
// 给三毛一只枪 | |
sanMao.setGun(new Rifle()); // 给三毛的是步枪, 也能够给三毛手枪 或者是 机枪 | |
// 三毛开始杀敌人了 | |
sanMao.killEnemy();} | |
} |
有人,有枪,有场景,运行后果如下所示。
在这个过程中,咱们能够给三毛这个士兵一把步枪,当然也能够给三毛其余的枪,只须要批改 sanMao.setGun(new Rifle()) 批改成 sanMao.setGun(new MachineGun()) 即可。在编写 Soldier 士兵类基本就不必晓得是哪个型号的枪被传入。
留神 在类中调用其余类时务必应用父类或接口,如果不能应用父类或接口,则阐明类的设计曾经违反了 LSP 准则。
咱们再来想一想,如果咱们有一个玩具手枪,该如何定义呢?咱们先在类图上减少一个类 ToyGun,而后继承于 AbstractGun 类,批改后的类图如图所示。
正文完