Liskov替换原则(The Liskov Substitution Principle)

子类型(subtype)必须能够替换掉它们的基类型(base type)。

一个违反LSP的简单例子

public class AntiLspDemo {public void drawShape(final Shape shape) {if (shape.getItsType() == ShapeType.Square) {final Square square = (Square) shape;square.draw();} else if (shape.getItsType() == ShapeType.Circel) {final Circle circle = (Circle) shape;circle.draw();}}
}enum ShapeType {/*** 正方形.*/Square,/*** 圆形.*/Circel
}class Point {private double x;private double y;// get/set...
}class Shape {private ShapeType itsType;/*** 获取itsType.* @return the itsType*/public ShapeType getItsType() {return itsType;}/*** 设置itsType.* @param newItsType the itsType to set*/public void setItsType(ShapeType newItsType) {itsType = newItsType;}}class Circle extends Shape {private Point itsCenter;private double itsRadius;public Circle() {this.setItsType(ShapeType.Circel);}public void draw() {System.out.println("绘制Circle...");}
}class Square extends Shape {private Point itsTopLeft;private double itsSide;public Square() {this.setItsType(ShapeType.Square);}public void draw() {System.out.println("绘制Square...");}
}

正方形和矩形,更微妙的违规

我们经常说继承是IS-A(“是一个”)关系。如果一个新类型的对象被认为和一个已有类的对象之间满足IS-A关系,那么这个新对象的类应该从这个已用对象的类派生。

一个正方形是一个矩形,所以Square类就应该派生在Rectangle类。不过,这将带来一些微妙但极为值得重视的问题。

public class Rectangle {/*** 左上角坐标.*/private Point topLeft;/*** 宽度.*/private double width;/*** 高度.*/private double height;/*** 获取topLeft.* @return the topLeft*/public Point getTopLeft() {return topLeft;}/*** 设置topLeft.* @param newTopLeft the topLeft to set*/public void setTopLeft(Point newTopLeft) {topLeft = newTopLeft;}/*** 获取width.* @return the width*/public double getWidth() {return width;}/*** 设置width.* @param newWidth the width to set*/public void setWidth(double newWidth) {width = newWidth;}/*** 获取height.* @return the height*/public double getHeight() {return height;}/*** 设置height.* @param newHeight the height to set*/public void setHeight(double newHeight) {height = newHeight;}}public class Square extends Rectangle {public void setWidth(double width) {super.setWidth(width);super.setHeight(width);}public void setHeight(double height) {super.setWidth(height);super.setHeight(height);}
}

真正的问题

Square类没有违反正方形的不变性,但是Square派生自Rectangle,Square类违反了Rectangle类的不变性。

public void g(Rectangle r) {r.setWidth(5);r.setHeight(4);assert(r.area() == 20)
}

有效性并非本质属性

一个模型,如果孤立地看,并不具有真正意义上的有效性。模型的有效性只能通过它的Client程序来体现。这又是一个实践TDD的好理由。

IS-A是关于行为的

对于那些不是g的调用者而言,正方形可以是长方形,但是从g的角度,Square对象绝对不是Rectangle对象。Square对象的行为方式和函数g所期望的Rectangle对象的行为方式不相容。从行为方式的角度来看,Square不是Rectangle,对象的行为方式才是软件真正所关注的。

基于契约设计

基于契约设计(Design By Contract),类的编写者显示地规定针对该类的契约。契约是通过为每个方法声明的前置条件(preconditions)和后置条件(postconditions)来指定的。要执行一个方法,前置条件必须为真。执行完毕后,保证后置条件为真。

Rectangle.setWidth(double w)的后置条件:
assert((width == w) && (height == old.height));

派生类的前置条件和后置条件规则是:

在重新声明派生类中的例程(routine)时,

只能使用相等或更弱的前置条件,只能使用相等或更强的后置条件。

Liskov替换原则(LSP)相关推荐

  1. liskov替换原则_坚实原则:Liskov替代原则

    liskov替换原则 以前,我们深入研究了坚实的原则,包括单一责任和开放/封闭原则. Liskov替代原则(LSP)是子类型关系的一种特殊定义,称为(强)行为子类型, 假设对象S是对象T的子类型,则可 ...

  2. 五大软件设计原则学习笔记3——Liskov 替换原则

    五大软件设计原则SOLID: 单一职责原则(Single responsibility principle,SRP) 开放封闭原则(Open–closed principle,OCP) Liskov ...

  3. 深入理解JavaScript系列(8):S.O.L.I.D五大原则之里氏替换原则LSP

    前言 本章我们要讲解的是S.O.L.I.D五大原则JavaScript语言实现的第3篇,里氏替换原则LSP(The Liskov Substitution Principle ). 英文原文:http ...

  4. 【转】深入理解JavaScript系列(8):S.O.L.I.D五大原则之里氏替换原则LSP

    前言 本章我们要讲解的是S.O.L.I.D五大原则JavaScript语言实现的第3篇,里氏替换原则LSP(The Liskov Substitution Principle ). 英文原文:http ...

  5. liskov替换原则_构造函数与打破Liskov替代原则

    liskov替换原则 At the risk of being targeted by the PHP hate-mongers, I must confess that I'm pretty com ...

  6. Liskov替换原则

    Liskov替换原则 文章目录 Liskov替换原则 案例引入 如何理解 子类型可以替换 基类型 ? 违反LSP的危害 总结 参考文档 今天我继续来说 软件设计的另一个原则, LSP原则 里氏代换原则 ...

  7. 编码最佳实践——Liskov替换原则

    Liskov替换原则(Liskov Substitution Principle)是一组用于创建继承层次结构的指导原则.按照Liskov替换原则创建的继承层次结构中,客户端代码能够放心的使用它的任意类 ...

  8. 设计原则:里式替换原则(LSP)

    系列文章 设计原则:单一职责(SRP) 设计原则:开闭原则(OCP) 设计原则:里式替换原则(LSP) 设计原则:接口隔离原则(ISP) 设计原则:依赖倒置原则(DIP) 何谓高质量代码? 理解RES ...

  9. 论重写和里式替换原则(LSP)

    对于重写的原则,很多人总是巴拉巴拉一大堆两同两小一大,记不住不说,还不明白为啥,搞得花里胡哨. 其实万事万物的结果自然有其原理,JAVA作为一门编程语言,其更是有严格的语言规范和简洁性要求. 那为啥重 ...

最新文章

  1. Python3 的urllib实例
  2. Oracle 学习笔记:Backup Recovery 常用命令
  3. windbg-奔溃生成的dump文件
  4. 如何在Word里面自动生成目录
  5. 自己Ubuntu里面的一些小脚本
  6. 基础省选+NOI-第7部分 概率统计与多项式
  7. 京东淘汰“三类人”,近 18 万员工懵了?!
  8. Delphi 与 DirectX 之 DelphiX(60): TDIB.DoTrace();
  9. HTML5 Media 原创翻译——第一章(持续更新中)
  10. AWVS13安装教程
  11. 安全测试-Drozer安全测试框架实践记录篇
  12. UMD算法讲义——Lecture 2:算法设计:稳定婚姻问题
  13. win10系统cpu内核或逻辑核心缺少缺少,解决办法
  14. 工厂模式及在Spring中的应用
  15. 将Python程序打包成exe文件
  16. linux下文件属性drwxr-xr-x各是什么意思
  17. linux命令行的杠“-”、杠杠“--”以及无杠
  18. 【测试沉思录】17. 性能测试中的系统资源分析之四:网络
  19. 计算机网络三元组,计算机网络chap07 传输层(1) - 三元组 五元组.pdf
  20. 榆熙电商:为何购物旗舰店选择优于其他?

热门文章

  1. Reactor三种线程模型与Netty线程模型
  2. 论文浅尝 | 知识图谱的单样本关系学习
  3. python中模块、函数与各个模块之间的调用
  4. 每日优鲜小程序基础组件介绍
  5. PC_excel完毕一列英文小写变大写
  6. pidgin-qq可以使用QQ2012协议了
  7. 设计模式第三集——装饰者模式(Decorator)
  8. 大型JavaScript应用程序架构模式
  9. 计算机网络(三)-体系结构
  10. 【剑指offer】面试题35:复杂链表的复制(Java 实现)