使用里氏替换原则解决实际问题
下面介绍一个经典的业务场景,用正方形、矩形和四边形的关系来说明里氏替换原则。
我们都知道正方形是一个特殊的长方形,首先创建一个长方形父类 Rectangle,代码如下。
里氏替换原则只存在于父类和子类之间,约束继承泛滥。再来创建一个基于长方形与正方形共同的抽象——四边形 QuardRangle 接口,代码如下。
下面修改代码,增加 getDiscountPrice() 方法。JavaDiscountCourse 类代码如下:
我们都知道正方形是一个特殊的长方形,首先创建一个长方形父类 Rectangle,代码如下。
public class Square extends Rectangle { private long length; public long getLength() { return length; } public void setLength(long length) { this.length = length; } @Override public long getHeight() { return getLength(); } @Override public void setHeight(long height) { setLength(height); } @Override public void setWidth(long width) { setLength(width); } @Override public long getWidth() { return getLength(); } }在测试类中,创建 resize() 方法。根据逻辑,长方形的宽应该大于等于高,我们让高一直自增,直到高等于宽变成正方形,代码如下。
public static void resize(Rectangle rectangle) { while (rectangle.getWidth() >= rectangle.getHeight()) { rectangle.setHeight(rectangle.getHeight() + 1); System.out.println("width: " + rectangle.getWidth() + ",Height: " + rectangle.getHeight()); } System.out.println("Resize End,width:" + rectangle.getWidth() + " ,Height:" + rectangle.getHeight()); }客户端测试代码如下:
public static void main(String[] args) { Rectangle rectangle = new Rectangle(); rectangle.setWidth(20); rectangle.setHeight(10); resize(rectangle); }运行结果如下:
width: 20,Height: 11 width: 20,Height: 12 width: 20,Height: 13 width: 20,Height: 14 width: 20,Height: 15 width: 20,Height: 16 width: 20,Height: 17 width: 20,Height: 18 width: 20,Height: 19 width: 20,Height: 20 width: 20,Height: 21 Resize End,width:20 ,Height:21由运行结果可知,高比宽还大,这在长方形中是一种非常正常的情况。再看下面的代码,把长方形替换成它的子类正方形,修改客户端测试代码如下:
public static void main(String[] args) { Square square = new Square(); square.setLength(10); resize(square); }此时,运行出现了死循环,违背了里氏替换原则,在将父类替换成子类后,程序运行结果没有达到预期。因此,代码设计是存在一定风险的。
里氏替换原则只存在于父类和子类之间,约束继承泛滥。再来创建一个基于长方形与正方形共同的抽象——四边形 QuardRangle 接口,代码如下。
public interface QuardRangle { long getWidth(); long getHeight(); }修改长方形 Rectangle 类的代码如下。
public class Rectangle implements QuardRangle{ private long height; //高 private long width; //宽 public long getHeight() { return height; } public void setHeight(long height) { this.height = height; } public void setWidth(long width) { this.width = width; } public long getWidth() { return width; } }修改正方形 Square 类的代码如下。
public class Square implements QuardRangle { private long length; public long getLength() { return length; } public void setLength(long length) { this.length = length; } @Override public long getHeight() { return getLength(); } @Override public long getWidth() { return getLength(); } }此时,如果把 resize() 方法的参数换成四边形 QuardRangle 类,方法内部就会报错。因为正方形已经没有了 setWidth() 和 setHeight() 方法,所以,为了约束继承泛滥,resize() 方法的参数只能用长方形 Rectangle 类。
拓展
在讲开闭原则的时候,我们埋下了一个伏笔。在 JavaDiscountCourse 类中获取折扣价格时重写了父类的 getPrice() 方法,增加了一个获取源码的 getOriginPrice() 方法,这明显违背了里氏替换原则。下面修改代码,增加 getDiscountPrice() 方法。JavaDiscountCourse 类代码如下:
public class JavaDiscountCourse extends JavaCourse { public JavaDiscountCourse(Integer id, String name, Double price) { super(id, name, price); } public Double getDiscountPrice() { return super.getPrice() * 0.8; } }
所有教程
- C语言入门
- C语言编译器
- C语言项目案例
- 数据结构
- C++
- STL
- C++11
- socket
- GCC
- GDB
- Makefile
- OpenCV
- Qt教程
- Unity 3D
- UE4
- 游戏引擎
- Python
- Python并发编程
- TensorFlow
- Django
- NumPy
- Linux
- Shell
- Java教程
- 设计模式
- Java Swing
- Servlet
- JSP教程
- Struts2
- Maven
- Spring
- Spring MVC
- Spring Boot
- Spring Cloud
- Hibernate
- Mybatis
- MySQL教程
- MySQL函数
- NoSQL
- Redis
- MongoDB
- HBase
- Go语言
- C#
- MATLAB
- JavaScript
- Bootstrap
- HTML
- CSS教程
- PHP
- 汇编语言
- TCP/IP
- vi命令
- Android教程
- 区块链
- Docker
- 大数据
- 云计算