首页 > 代码库 > 里氏代换原则
里氏代换原则
什么是里氏代换原则了?
如果对于每一个类型T1的对象O1,都有类型为T2的对象O2,使得以T1定义的所有程序P在所有对象O1都代换成O2时,程序P没有变化,那么类型T2是类型T1的子类。也就是说,一个软件实体如果使用的是一个基类的话,那么一定适用其子类。
比喻:
public class A { }
public class B extends A { }
public class Tests { @Test public void tests() { A a = new A(); method(a); B b = new B(); method(b); } public void method(A a) { } }当B是A的子类时,如果有方法method(A a),那么method(new B())也一定成立
里氏代换原则是继承利用的基石。
这里来聊聊西方一个非常有名的例子,正方形是否是长方形的子类的总是。
public class Rectangle { private long width; private long height; public long getWidth() { return width; } public void setWidth(long width) { this.width = width; } public long getHeight() { return height; } public void setHeight(long height) { this.height = height; } }当width和height相等时,就得到正方形了,因为可以理解为长方形的对象中有一些是正方形,这样理解对吗?
那我们来看看正方形的源码
public class Square { private long side; public long getSide() { return side; } public void setSide(long side) { this.side = side; } }从上面的代码可以看出来,其实正方形并不是长方形的子类。
其实正方形不可以作为长方形的子类,为什么了?
假设我们现在有个类Square是Rectange的子类,如下:
public class Square extends Rectangle { private long side; public long getSide() { return side; } public void setSide(long side) { this.side = side; } @Override public long getHeight() { return getSide(); } @Override public long getWidth() { return getSide(); } @Override public void setHeight(long height) { setSide(height); } @Override public void setWidth(long width) { setSide(width); } }
只要width和height被赋值,那么width和height也会同时被复制,当定义一个resize方法,这个方法会将宽度不断增加,直到超过长度才停下来,如果传入的是一个Rectangle的话,这个方法没有问题,如果传入的是square的话,这个方法会引起溢出。
public class Tests { public void resize(Rectangle rectangle) { while (rectangle.getHeight() <= rectangle.getWidth()) { rectangle.setWidth(rectangle.getWidth() + 1); } } }
所以正方形不可以当成长方方形的子类。
ok,我们对代码进行重构下,正方形和长方形都 是四边形,那们发明一个加边形类,将长方形和正方形变成它的具体子类,这样就解决了长方形和正方形的关系不符合里氏代换原则的问题。
public interface QuadRange { public long getWidth(); public long getHeight(); }
public class Rectangle implements QuadRange { private long width; private long height; public long getWidth() { return width; } public void setWidth(long width) { this.width = width; } public long getHeight() { return height; } public void setHeight(long height) { this.height = height; } }
public class Square implements QuadRange { private long side; public long getSide() { return side; } public void setSide(long side) { this.side = side; } @Override public long getWidth() { return getSide(); } @Override public long getHeight() { return getSide(); }
<span style="font-family: Arial, Helvetica, sans-serif;">这样在基类里没有赋值方法,因此resize的方法就不能合适于QuadRange这样的基类,而只能适合于不同的具体子类Rectangle和Square,这样里氏代换原则不可能被破坏.</span>
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。