设计模式之二里氏替换原则(LSP)

里氏替换原则

约定了继承的使用规范:

  • 子类应该实现所有的父类方法。
    对于抽象类来说,如果其子类不是抽象类,则必须实现所有的抽象方法。抽象类定义了一个模板,子类实现模板中的方法,在调用的时通过传递抽象类的子类对象决定到底采用抽象类的哪个实现。
    案例:一个场景中,士兵可以使用不同的枪射击敌人。这里可以抽象出三类对象, 场景-士兵-枪,关系如下


    场景UML图

    代码如下

AbstractGun.java
public abstract class AbstractGun {
    public abstract void shoot();
}
Pistol.java
public class Pistol extends AbstractGun {
    @Override
    public void shoot() {
        System.out.println("使用手枪射击...biu~~");
    }
}
Rifle.java
public class Rifle extends AbstractGun {
    @Override
    public void shoot() {
        System.out.println("步枪射击... peng~~");
    }
}
MachineGun.java
public class MachineGun extends AbstractGun {
    @Override
    public void shoot() {
        System.out.println("机关枪射击...tu~~");
    }
}
Soldier.java
public class Soldier {
    private AbstractGun gun;
    public void setGun(AbstractGun gun){
        this.gun = gun;
    }
    public void killEnemy(){
        System.out.println("士兵开始射击...");
        gun.shoot();
    }
}
Client.java
public class Client {
    public static void main(String[] args) {
        Soldier soldier = new Soldier();
        soldier.setGun(new Rifle());
        soldier.killEnemy();
    }
}

当我们需要改变使用的枪时候,只需要在Client里面修改setGun的参数,部需要修改Soldier的相关方法,提高了代码可重用性。

  • 子类可以有自己独有的方法和属性。
    基于以上的代码和关系,定义狙击手和狙击枪。


    子类可以具有自己的方法
Snipper.java
public class Snipper {
    private AUG aug;
    public void setRifle(AUG aug){
        this.aug = aug;
    }
    public void killEnemy(){
        aug.zoomOut();
        aug.shoot();
    }
}
AUG.java
public class AUG extends Rifle{
    public void zoomOut(){
        System.out.println("开始使用瞄准镜观察~~");
    }
    public void shoot(){
        System.out.println("AUG开始射击... peng~~");
    }
}
  • 覆写或实现父类方法时输入参数可以扩大
Father.java
public class Father{
    public Collection doSomething(HashMap map){
        System.out.println("调用父类----------------------");
        return map.values();
    }
}
Child.java
public class Child extends Father{
    public Collection doSomething(Map map){
        System.out.println("调用子类----------------------");
        return map.values();
    }
}
Client.java
public class Client{
    public static void invoker(){
        Father f = new Father();//-------------------------------------------------------------------
        HashMap map = new HashMap();
        f.doSomething(map);
    }
    public static void main(String[] args) {
        invoker();
    }
}

根据里氏替换规则,父类出现的地方子类就可以出现,所以这里的Father对象可以替换为Child对象。

  • 覆写或实现父类方法时输出结果可以缩小
    针对上一个案例,子类的同名方法的返回值类型必须与父类相同或者是父类的子类。分两种情况,如果是override,正好这是override的要求)如果是overload,类型必须相同,否则不构成overload。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 32,256评论 18 399
  • (一)Java部分 1、列举出JAVA中6个比较常用的包【天威诚信面试题】 【参考答案】 java.lang;ja...
    独云阅读 11,943评论 0 62
  • 3月10日早4:25起,换装西昌馬短袖衫,黑短裤,手套,长袜膝下,特步跑鞋。 4:40下楼(出發前有...
    灵歌的简书阅读 1,148评论 0 0
  • 我无法阻止一场雪 诗/刘锋 那场雪,一直行进在路上 它用一朵梅的暗香,为我 捎来隐隐寒意。冰点迫近 一场风带来的讯...
    四川刘锋阅读 2,844评论 9 23
  • 社会里,职场中,人来人往是很正常的事。即便相处时间不长,也算是缘分。当然,每个人离开一家公司都有不同的理由,但不管...
    聂荣恒阅读 10,920评论 0 50

友情链接更多精彩内容