里氏代換原則講的是基類和子類的關係。只有這種關係存在是里氏代換原則才存在,不然不存在。若是兩個類A、B違反了里氏代換原則時刻從如下兩個重構方案中選擇一種:java
(1)建立一個新的抽象類C,做爲兩個具體類的超類,將A、B共同的行爲移動到C中,從而解決兩者行爲是不一致的問題。
ide
(2)將B到A的繼承關係改成委派關係。
this
本文例子描述的是第一種重構方法,第二種參見合成/聚合複用原則一文。
spa
正方形可不能夠被當作長方形的子類?
code
package Liskov.version1; 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; } }
package Liskov.version1; public class Square { private long side; public long getSide() { return side; } public void setSide(long side) { this.side = side; } }
由於此時的正方形類不是長方形類的子類, 所以不存在里氏代換關係。
對象
那若是把正方形類定義爲長方形類的子類呢,會有什麼問題?
繼承
package Liskov.version2; import Liskov.version1.Rectangle; public class Square extends Rectangle{ private int side; public int getSide() { return side; } public void setSide(int side) { this.side = side; } }
package Liskov.version2; import Liskov.version1.Rectangle; public class smartTest { public void resize(Rectangle r){ while(r.getHeight() <= r.getWidth()) r.setWidth(r.getWidth()+1); } }
若是smartTest類傳入的是Rectangle對象,resize()方法將不斷增長,直至超過長度而聽下來;若是傳入的是Square對象時,正方形少的邊會不斷增長直至溢出。get
代碼重構,依據白馬黑馬都是馬的觀點io
package Liskov.version3; public interface Quardrangle { public long getHeight(); public long getWeight(); }
package Liskov.version3; public class Rectangle implements Quardrangle { private long width; private long height; public long getWidth() { return width; } public long getHeight() { return height; } public void setWidth(long width) { this.width = width; } public void setHeight(long height) { this.height = height; } }
package Liskov.version3; public class Square implements Quardrangle{ private long side; public long getSide() { return side; } public void setSide(long side) { this.side = side; } @Override public long getHeight() { // TODO Auto-generated method stub return side; } @Override public long getWidth() { // TODO Auto-generated method stub return side; } }
那麼破壞里氏代換原則的問題是怎麼避免的呢?祕密在於基類Quadrangle沒有賦值方法,所以相似於smartTest的resize()方法不可能適用於Quadrangle類型,只能適用於不一樣的具體子類Rectangle和Square,所以里氏代換原則不可能被破壞。
class