专栏首页大数据进阶设计模式-里氏替换

设计模式-里氏替换

先来看个最正宗的定义 如果对每一个类型为S的对象o1,都有类型为T的对 象o2,使得以T定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变 化,那么类型S是类型T的子类型。 我们再来看一个通俗易懂的定义: 所有引用基类的地方必须能透明地使用其子类的 对象。 下面来看一下uml图

public abstract class AbstractGun {
    //枪用来干什么的?杀敌!
    public abstract void shoot();
}    
//手枪、步枪、机枪的实现类如代码清单2-2所示。 代码清单2-2 手枪、步枪、机枪的实现类
public class Handgun extends AbstractGun { 
    //手枪的特点是携带方便,射程短
    @Override
    public void shoot() {
        System.out.println("手枪射击...");
    } 
}
public class Rifle extends AbstractGun{ 
    //步枪的特点是射程远,威力大
    public void shoot(){
        System.out.println("步枪射击...");
    } 
}
public class MachineGun extends AbstractGun{ 
    public void shoot(){
        System.out.println("机枪扫射...");
    }
}
//有了枪支,还要有能够使用这些枪支的士兵,其源程序如士兵的实现类
public class Soldier { 
    //定义士兵的枪支
    private AbstractGun gun;
    //给士兵一支枪
    public void setGun(AbstractGun _gun){
        this.gun = _gun;
    }

    public void killEnemy(){
        System.out.println("士兵开始杀敌人..."); 
        gun.shoot();
    } 
}
//定义士兵使用枪来杀敌,但是这把枪是抽象的,具体是手枪还是步枪需 要在上战场前(也就是场景中)前通过setGun方法确定
public class Client {
    public static void main(String[] args) {
        //产生三毛这个士兵
        Soldier sanMao = new Soldier(); 
        //给三毛一支枪
        sanMao.setGun(new Rifle()); 
        sanMao.killEnemy();
    } 
}

在项目中难免会遇到一些比较特殊的子类,此时建议采用聚合或者组合来进行

比如如下

public class ToyGun extends AbstractGun { 
    //玩具枪是不能射击的,但是编译器又要求实现这个方法,怎么办?虚构一个呗! 
    @Override
    public void shoot() {
    //玩具枪不能射击,这个方法就不实现了
    } 
}
public class Client {
    public static void main(String[] args) {
        //产生三毛这个士兵
        Soldier sanMao = new Soldier(); 
		sanMao.setGun(new ToyGun()); 
		sanMao.killEnemy();
    } 
}

此种情况建议采用如下的方式进行实现 同样我们来看一下uml图

public class AUG extends Rifle { 
    //狙击枪都携带一个精准的望远镜 
    public void zoomOut(){
        System.out.println("通过望远镜察看敌人..."); 
		public void shoot(){
       		System.out.println("AUG射击...");
    } 
} 
public class Snipper {
    public void killEnemy(AUG aug){
        //首先看看敌人的情况,别杀死敌人,自己也被人干掉 
		aug.zoomOut();
        //开始射击
        aug.shoot();
    } 
}
public class Client {
    public static void main(String[] args) {
        //产生三毛这个狙击手
        Snipper sanMao = new Snipper(); 
        sanMao.setRifle(new AUG()); 
        sanMao.killEnemy();
    } 
}

为了满足设计满足“里氏替换”原则,子类不能太有个性,子类重载父类的方法时,入参要更加宽泛,大于等于父类,返回值要收缩,要小于等于父类。 下面来看一下具体的代码描述

public class Father {
    public Collection doSomething(HashMap map){
        System.out.println("父类被执行..."); 
        return map.values();
    }
}
public class Son extends Father { 
    //放大输入参数类型
    public Collection doSomething(Map map){ 
        System.out.println("子类被执行..."); 
        return map.values();
    } 
}
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();
    } 
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 设计模式-依赖倒置

    yiduwangkai
  • 设计模式-单例

    登记模式:是为了克服饿汉式单例类及懒汉式单例类均不可继承的缺点而设计的。他的子类实例化的方式只能是懒汉式

    yiduwangkai
  • spark 编写udaf函数求中位数

    yiduwangkai
  • Java基础-day11-接口;多态案例练习

    Java基础-day11-接口&多态案例练习 题目要求1(多态): 定义家类 方法:饲养动物 动物类: 属性:年龄、姓名 方法:吃饭、睡觉 猫类、狗类、猪类均为...

    Java帮帮
  • 第76节:Java中的基础知识

    设置环境,安装操作系统,安装备份,就是镜像,jdk配置环境,eclipse下载解压即可使用,下载tomcat

    达达前端
  • 自定义注解与常用设计模式

    注解分为:内置注解,自定义注解。内置注解就是JDK 自带的,而自定义注解则是自己定义的比如许多框架(spring) 用到的

    斯文的程序
  • 策略模式——运筹帷幄

    三国情景再现: 诸葛亮在刘备去东吴招亲之前,特授予伴郎赵云三个锦囊,说是按天机拆开解决棘手问题。

    100000860378
  • 依赖注入容器-- Autofac

    Autofac---Autofac是一款IOC框架,比较于其他的IOC框架,如Spring.NET,Unity,Castle等等所包含的,它很轻量级性能上非常高...

    小世界的野孩子
  • Java面向对象之抽象类,接口

    抽象类: 含有抽象方法的类被声明为抽象类 抽象方法由子类去实现 含有抽象方法的类必须被声明为抽象类 抽象类被子类继承,子类(如果不是抽象类)必须重写抽象类中...

    二十三年蝉
  • 图解Java设计模式

    只要是在类中用到了对方,那么他们之间就存在依赖关系。如果没有对方,连编 绎都通过不了。

    编程之心

扫码关注云+社区

领取腾讯云代金券