里氏替换原则(LSP)描述了,子类可以扩展父类的功能,但是不能改变父类原有的功能
优点:
- 里氏替换时实现开闭原则的重要方式之一
- 避免了重写父类造成了可复用性变差的缺点
- 类的扩展不会对已有系统引入新的异常,降低代码出错的可能
- 加强了程序的健壮性
实现方式:最直接的应用场景就是子类在继承父类的时候,除了完成扩展功能之外尽量避免重写父类的方法
反例:枪可以射击和杀人,那么玩具枪呢?
public static void main(String[] args) {// 手枪射击并杀人Gun handgun = new HandGun();handgun.shoot();// 手枪射击handgun.kill(); // 手枪杀人// 玩具枪射击并杀人Gun toyGun = new ToyGun();toyGun.shoot(); // 玩具枪射击toyGun.kill(); // java.lang.RuntimeException: 玩具枪不能杀人!}// 基类interface Gun{// 射击void shoot();// 杀人void kill();}// 手枪static class HandGun implements Gun{@Overridepublic void shoot() {System.out.println("手枪射击");}@Overridepublic void kill() {System.out.println("手枪杀人");}}// 玩具枪static class ToyGun implements Gun{@Overridepublic void shoot() {System.out.println("玩具枪射击");}@Overridepublic void kill() {throw new RuntimeException("玩具枪不能杀人!");}}
正例:针对以上问题,应该再抽象一个只会枪的通用功能的基类【射击】,如下:
public static void main(String[] args) {// 手枪射击杀人Gun handGun = new HandGun();handGun.shoot(); // 手枪射击handGun.kill(); // 手枪杀人// 玩具枪射击AbstractGun toyGun = new ToyGun();toyGun.shoot(); // 玩具枪射击}// 抽象基类,只具备射击功能interface AbstractGun{// 射击void shoot();}// 基类,扩展了杀人功能interface Gun extends AbstractGun{// 射击void kill();}// 手枪static class HandGun implements Gun {@Overridepublic void shoot() {System.out.println("手枪射击");}@Overridepublic void kill() {System.out.println("手枪杀人");}}// 玩具枪static class ToyGun implements AbstractGun {@Overridepublic void shoot() {System.out.println("玩具枪射击");}}
