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

举报
ShaderJoy 发表于 2021/12/30 01:13:41 2021/12/30
【摘要】 里氏置换原则(Liskov Substitution Principle),简称 LSP 定义: Functions that use pointers or references to base classes must be able to use objects of derived classes without knowi...

里氏置换原则(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层含义:

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

定义一个抽象类


  
  1. public abstract class ViewPoint {
  2. //去丽江旅游
  3. public abstract void where();
  4. }


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

 


  
  1. public class Lijiang extends ViewPoint {
  2. @Override
  3. public void where() {
  4. System.out.println("欢迎来到丽江...");
  5. }
  6. }
  7. ?
  8. public class Zhangjiajie extends ViewPoint {
  9. @Override
  10. public void where() {
  11. System.out.println("欢迎来到张家界...");
  12. }
  13. }


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

 


  
  1. public class Tutu {
  2. //定义要旅游的景点
  3. private ViewPoint viewpoint;
  4. //涂涂要去的景点
  5. public void setViewPoint(ViewPoint viewpoint)
  6. {
  7. this.viewpoint = viewpoint;
  8. }
  9. public void travelTo()
  10. {
  11. System.out.println("涂涂要去旅游了");
  12. viewpoint.where();
  13. }
  14. }


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

 


  
  1. public class Sence {
  2. public static void main(String args[])
  3. {
  4. Tutu tutu = new Tutu();
  5. //设置要去的旅游景点
  6. tutu.setViewPoint(new Lijiang());
  7. tutu.travelTo();
  8. }
  9. }

运行结果:

 


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

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

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

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

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

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


  
  1. import java.util.Collection;
  2. import java.util.HashMap;
  3. public class Father {
  4. public Collection say(HashMap map)
  5. {
  6. System.out.println("父类被执行...");
  7. return map.values();
  8. }
  9. }

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

 


  
  1. import java.util.Collection;
  2. import java.util.Map;
  3. /*
  4. * 子类继承了父类的所有属性
  5. */
  6. public class Son extends Father {
  7. //方法输入参数类型
  8. public Collection say(Map map)
  9. {
  10. System.out.println("子类被执行...");
  11. return map.values();
  12. }
  13. }


场景类

 


  
  1. import java.util.HashMap;
  2. public class Home {
  3. public static void main(String args[])
  4. {
  5. invoke();
  6. }
  7. public static void invoke()
  8. {
  9. //父类存在的地方,子类就应该能够存在
  10. //Father f = new Father();
  11. Son s = new Son();
  12. HashMap map = new HashMap();
  13. //f.say(map);
  14. s.say(map);
  15. }
  16. }

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

 

父类被执行...
 

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


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

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

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

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

 

文章来源: panda1234lee.blog.csdn.net,作者:panda1234lee,版权归原作者所有,如需转载,请联系作者。

原文链接:panda1234lee.blog.csdn.net/article/details/9137377

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。