设计模式--6大原则--里氏置换原则

里氏置换原则(Liskov Substitution Principle),简称 LSP

定义:

Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

所有引用基类的地方必须能够透明的使用其子类对象。

也就是说,只要父类出现的地方子类就能够出现,而且替换为子类不会产生任何错误或异常。但是反过来,子类出现的地方,替换为父类就可能出现问题了。

这个原则是为良好的继承定义一个规范,简单的讲,有4层含义:

一、子类必须完全实现父类的方法

定义一个抽象类

public abstract class ViewPoint {
    //去丽江旅游
    public abstract void where();
}


下面两个类是实现这个抽象类

 

public class Lijiang extends ViewPoint {
 
    @Override
    public void where() {
        System.out.println("欢迎来到丽江...");
    }
 
}
?
public class Zhangjiajie extends ViewPoint {
 
    @Override
    public void where() {
        System.out.println("欢迎来到张家界...");
    }
 
}


人物是涂涂,在里面设置类类型来传递参数。此时涂涂要去的旅游景点还是抽象的

 

public class Tutu {
    //定义要旅游的景点
    private ViewPoint viewpoint;
    //涂涂要去的景点
    public void setViewPoint(ViewPoint viewpoint)
    {
        this.viewpoint = viewpoint;
    }
     
    public void travelTo()
    {
        System.out.println("涂涂要去旅游了");
        viewpoint.where();
    }
}


场景类。设置具体要去的景点

 

public class Sence {
    public static void main(String args[])
    {
        Tutu tutu = new Tutu();
        //设置要去的旅游景点
        tutu.setViewPoint(new Lijiang());
        tutu.travelTo();
    }
}

运行结果:

 

涂涂要去旅游了
欢迎来到丽江...

二、子类可以有自己的特性

也就是说在类的子类上,可以定义其他的方法或属性

三、覆盖或者实现父类的方法时输入参数(的范围)可以被放大

父类能够存在的地方,子类就能存在,并且不会对运行结果有变动。反之则不行。

父类,say() 里面的参数是 HashMap 类型,是 Map 类型的子类型。(因为子类的范围应该比父类大)

import java.util.Collection;
import java.util.HashMap;
 
public class Father {
    public Collection say(HashMap map)
    {
        System.out.println("父类被执行...");
        return map.values();
    }
}

子类,say() 里面的参数变成了 Map 类型,Map范围比HashMap类型大,符合LSP原则。注意这里的 say 不是覆写父类的 say,因为参数类型不同。而是重载。

 

import java.util.Collection;
import java.util.Map;
 
/*
 * 子类继承了父类的所有属性
 */
public class Son extends Father {
    //方法输入参数类型
    public Collection say(Map map)
    {
        System.out.println("子类被执行...");
        return map.values();
    }
}


场景类

 

import java.util.HashMap;
 
public class Home {
    public static void main(String args[])
    {
        invoke();
    }
     
    public static void invoke()
    {
        //父类存在的地方,子类就应该能够存在
        //Father f = new Father();
        Son s = new Son();
        HashMap map = new HashMap();
        //f.say(map);
        s.say(map);
    }
}

无论是用父类还是子类调用 say 方法,得到的结果都是

 

父类被执行...

但是,如果将上面 Father 里的 say 参数改为 Map,子类 Son 里的 say 参数改为 HashMap,得到的结果就变成了

f.say(map)结果:父类被执行...
s.say(map)结果: 子类被执行...

这样会造成逻辑混乱。所以子类中方法的前置条件必须与父类中被覆写的前置条件相同或者更宽。

四、覆写或者实现父类的方法时输出结果可以被缩小

其实与上面的类似,也就是父类能出现的地方子类就可以出现,而且替换为子类不会产生任何错误或者异常,使用者也无需知道是父类还是子类。但是反过来就不行了,有子类出现的地方,父类未必就适应。(毕竟子类的范围要>=父类的范围)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值