LSP

(里氏代换原则)

编辑

本词条缺少 名片图,补充相关内容使词条更完整,还能快速升级,赶紧来 编辑吧!
LSP是里氏代换原则的英文Liskov Substitution Principle的缩写,LSP讲的是基类和子类的关系。只有当这种关系存在时,里氏代换关系才存在。
中文名
里氏代换原则
外文名
Liskov Substitution Principle

目录

  1. 1 LSP (Liskov Substitution Principle)
  1. 2 表述
  2. 3 理解
  3. 4 总结
  1. 5 备注
  2. 6 举例

LSP (Liskov Substitution Principle)

编辑

Liskov替换原则:子类型必须能够替换它们的基类型

表述

编辑

1. 如果每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都代换为o2时,程序P的行为没有变化,那么类型T2是类型T1的子类型。
2. 换言之,一个软件实体如果使用的是一个基类的话,那么一定适用于其子类,而且它根本不能察觉出基类对象和子类对象的区别。只有衍生类替换基类的同时软件实体的功能没有发生变化,基类才能真正被复用。
3.  里氏代换原则由Barbar Liskov(芭芭拉.里氏)提出,是继承复用的基石。
4. 一个继承是否符合 里氏代换原则,可以判断该继承是否合理(是否隐藏有缺陷)。

理解

编辑

(1) 应当尽量从抽象类继承,而不从具体类继承。
一般而言,如果有两个具体类A、B有继承关系,那么一个最简单的修改方案是建立一个抽象类C,然后让类A和B成为抽象类C的子类。即如果有一个由继承关系形成的 等级结构的话,那么在等级结构的树形图上面所有的树叶节点都应当是具体类,而所有的树枝节点都应当是抽象类或者接口。

总结

编辑

1. 为了保持LSP,所有子类必须符合使用基类的client所期望的行为。
2. 一个子类型不得具有比基类型(base type)更多的限制,可能这对于基类型来说是合法的,但是可能会因为违背子类型的其中一个额外限制,从而违背了LSP!
3. LSP保证一个子类总是能够被用在其基类可以出现的地方!

备注

编辑

LSP讲的是基类和子类的关系。只有当这种关系存在时,里氏代换关系才存在。如果两个具体的类A,B之间的关系违反了LSP的设计,(假设是从B到A的继承关系)那么根据具体的情况可以在下面的两种重构方案中选择一种。 创建一个新的抽象类C,作为两个具体类的超类,将A,B的共同行为移动到C中来解决问题。 从B到A的继承关系改为委派关系。
在进行设计的时候,我们尽量从抽象类继承,而不是从具体类继承。如果从继承等级树来看,所有 叶子节点应当是具体类,而所有的树枝节点应当是抽象类或者接口。当然这个只是一个一般性的指导原则,使用的时候还要具体情况具体分析。

举例

编辑

Composite模式,Proxy模式,Strategy模式
里氏代换原则(Liskov Substitution Principle)
里氏代换原则是由麻省理工学院(MIT)计算机科学实验室的Liskov女士,在1987年的OOPSLA大会上发表的一篇文章《Data Abstraction and Hierarchy》里面提出来的,主要阐述了有关继承的一些原则,也就是什么时候应该使用继承,什么时候不应该使用继承,以及其中的蕴涵的原理。2002年,软件工程大师Robert C. Martin,出版了一本《Agile Software Development Principles Patterns and Practices》,在文中他把 里氏代换原则最终简化为一句话:"Subtypes must be substitutable for their base types",也就是说,子类必须能够替换成它们的基类。
我们把 里氏代换原则解释得更完整一些:在一个软件系统中,子类应该可以替换任何基类能够出现的地方,并且经过替换以后,代码还能正常工作。子类也能够在基类的基础上增加新的行为。
里氏代换原则是对开闭原则的补充,它讲的是基类和子类的关系。只有当这种关系存在时,里氏代换关系才存在。
"正方形是长方形"是一个理解 里氏代换原则的最经典的例子。在数学领域里,正方形毫无疑问是长方形,它是一个长宽相等的长方形。所以,应该让正方形继承自长方形。
长方形类如程序10-1所示。
程序10-1 长方形类Rectangle.java
package principle.liskovsubstitution; public class Rectangle { private int height; private int width; public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public int getWidth() { return width; } public void setWidth(int width) { this.width = width; } } 继承了长方形的 正方形类如程序10-2所示。
程序10-2 正方形类Square.java
package principle.liskovsubstitution; public class Square extends Rectangle { public void setWidth(int width) { super.setWidth(width); super.setHeight(width); } public void setHeight(int height) { super.setWidth(height); super.setHeight(height); } } 由于 正方形的长度和宽度必须相等,所以在方法setLength()和setWidth()中,对长度和宽度赋值相同。程序10-3所示的测试类中的函数zoom()用来增加长方形的长和宽。
程序10-3 测试类TestRectangle.java
package principle.liskovsubstitution; public class TestRectangle { public void zoom(Rectangle rectangle, int width, int height) { rectangle.setWidth(rectangle.getWidth() + width); rectangle.setHeight(rectangle.getHeight() + height); } } 显然,当增加的长度和宽度不同时,不能够将其中的长方形换成其子类正方形。这就违反了 里氏代换原则。
为了符合 里氏代换原则,我们可以为长方形和正方形创建一个父类Base,并在其中定义好共有的属性,并定义一个zoom() 抽象函数,如程序10-4所示。
程序10-4 父类Base.java
package principle.liskovsubstitution; public abstract class Base { private int height; private int width; public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public int getWidth() { return width; } public void setWidth(int width) { this.width = width; } public abstract void zoom(int width, int height); } 长方形类继承自该父类,并编写自己的zoom()实现函数,如程序10-5所示。
程序10-5 修改后的长方形类BaseRectangle.java
package principle.liskovsubstitution; public class BaseRectangle extends Base { public void zoom(int width, int height) { setWidth(getWidth() + width); setHeight(getHeight() + height); } } 正方形类也继承自该父类,并编写自己的zoom()实现函数,如程序10-6所示。
程序10-6 修改后的正方形类BaseSquare.java
package principle.liskovsubstitution; public class BaseSquare extends Base { public void setWidth(int width) { super.setWidth(width); super.setHeight(width); } public void setHeight(int height) { super.setWidth(height); super.setHeight(height); } public void zoom(int width, int height) { int length = (width + height) /2; setWidth(getWidth() + length); setHeight(getHeight() + length); } } 编写测试函数如程序10-7所示。
程序10-7 修改后的测试类BastTest.java
package principle.liskovsubstitution; public class BastTest { public void zoom(Base base, int width, int height) { base.zoom(width, height); } } 此时的Base类可以被它的子类Rectangle和Square所替代,而不用改变测试代码。这就是符合 里氏代换原则的编写方式。
由此可见,在进行设计的时候,我们尽量从抽象类继承,而不是从具体类继承。如果从继承等级树来看,所有 叶子节点应当是具体类,而所有的树枝节点应当是抽象类或者接口。当然这只是一个一般性的指导原则,使用的时候还要具体情况具体分析。

LSP (里氏代换原则)相关推荐

  1. 里氏代换原则(Liskov Substitution Principle)

    作用 它指导我们如何正确地进行继承与派生,并合理地重用代码! 定义 子类型必须能够替换掉它们的父类型.并出现在父类能够出现的任何地方. 这个就是尽量用多态的方法编程,也就是GRASP模式中的多态. 如 ...

  2. 系统设计原则之里氏代换原则

    之前讲述的"开-闭"原则是系统设计的主原则,做到这点是一件很不容易的工作.但是也不是高不可攀的,除此原则以外还有其他的一些设计原则为实现或者说尽可能的达到"开-闭&quo ...

  3. 里氏代换原则 (Liskov Substitution Principle, LSP)

    里氏代换原则 (Liskov Substitution Principle, LSP) 定义严格表达: 如果对每一个类型为T1的对象O1,都有类型为T2的对象O2,使得以T1定义的所有程序P在所有的对 ...

  4. 大话设计模式三之单一职责原则、开放-封闭原则、依赖倒置原则、里氏代换原则

    单一职责原则 单一职责原则(SRP),意思就是说,功能要单一.准确解释是,就一个类而言,应该仅有一个引起它变化的原因. 如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或 ...

  5. 北风设计模式课程---里氏代换原则

    北风设计模式课程---里氏代换原则 一.总结 一句话总结: 视频教程网上一定能找到做好笔记的博客,很大几率都不需要自己做笔记.比如北风设计模式课程,https://www.cnblogs.com/xi ...

  6. 面向对象设计原则实践:之四.里氏代换原则

    五.里氏代换原则(LSP--Liskov Substitution Principle) 1. 定义 a). 如果对每一个类型为S的对象o1,都有类型为T的对象o2, 使得以T定义的所有程序P在所有的 ...

  7. 里氏代换原则、依赖倒转原则

    里氏代换原则(LSP): 概念:子类型必须能够替换掉它们的父类型 解释:一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别.也就是说,在软件里面,把父类 ...

  8. 5.里氏代换原则依赖倒置原则

    里氏代换原则(LSP):子类型必须能够替换掉它们的父类(子类可以看做父类来使用) 依赖倒置原则:高层模块不应该依赖于低层模块,两个都应该依赖抽象:抽象不应该依赖细节,细节应该依赖抽象.

  9. 设计原则(3)-里氏代换原则

    本文转自:http://www.cnblogs.com/guoshiandroid/archive/2010/06/14/1758047.html 里氏代换原则 法海捉拿白蛇新解  应用场景举例: & ...

最新文章

  1. MMD_3b_StreamAlgorithms
  2. 你真的知道Python的字符串是什么吗?
  3. Error running app: Instant Run requires 'Tools | Android | Enable ADB integration' to be enabled
  4. java选填_java基础填空选择题
  5. java面试 泛型_Java面试题五:Java 的泛型, super T 和 extends T 的区别
  6. Linux 基础知识(2)---Linux内核空间内存申请函数kmalloc、kzalloc、vmalloc的区别
  7. EDA技术及应用实验2 h_adder程序
  8. 密码编码学与网络安全——原理与实践(第八版)------第4章 学习笔记
  9. C语言数字图像处理进阶---12光照特效滤镜
  10. R实战 | 山脊图(ridgeline plot)
  11. 3dmax基本物体放置操作1
  12. 团队作业五之旅游行业手机APP分析
  13. 王垠:我和Google的故事
  14. Oracle OIM 原理
  15. python 模拟考试系统_Project-OTS: Online Exam System written on Python 3. 基于Python 3的在线考试系统。...
  16. 关于“sin(10°)是无理数”的一个证明
  17. python附加篇setup打包篇
  18. java自动装箱拆箱原理
  19. 进行latex中的稿件运行时出现该错误,找不到STKaiti的字体
  20. ArcGIS Engine属性查询和空间查询联合查询要素

热门文章

  1. java 6 基础_Java基础(六)
  2. 360家庭卫士显示无法连接服务器,360智能摄像机连接失败原因 360智能摄像机连接失败解决办法...
  3. 美国高通仍是赢家,国产手机不仅抢它的高端芯片,中端芯片也抢发
  4. 考研复试专业课面试——数据结构
  5. mysql truncate命令
  6. MySQL 查询 limit 1000,10 和 limit 10 速度一样快吗? 深度分页如何破解
  7. Python表白代码:太秀了,用过的人都找到了对象...【满屏玫瑰盛开】
  8. 天堂2java gm设置_天堂2GM指令中英文对照
  9. Java Map集合练习
  10. java8 mysql datetime_在JDBC中使用Java8的日期LocalDate、LocalDateTime