動(dòng)機(jī)
當(dāng)我們?cè)O(shè)計(jì)程序模塊時(shí),我們會(huì)創(chuàng)建一些類層次結(jié)構(gòu),然后我們通過(guò)擴(kuò)展一些類來(lái)創(chuàng)建它們的子類。
我們必須確保子類只是擴(kuò)展而沒(méi)有替換父類的功能,否則當(dāng)我們?cè)谝延谐绦蚰K中使用它們時(shí)將會(huì)產(chǎn)生不可預(yù)料的結(jié)果。
里氏代換原則表明當(dāng)一個(gè)程序模塊使用基類時(shí),基類的引用可以被子類替換而不影響模塊的功能。
里氏代換原則
基類完全能夠被子類替代而不影響模塊的功能。
實(shí)例
對(duì)于多態(tài)來(lái)說(shuō)里氏代換原則好像是很顯然的事情,例如:
public void drawShape(Shape s) {// Code here.}
對(duì)于Shape的任何子類來(lái)說(shuō),drawShape方法都應(yīng)該能很好的工作。我們必須小心的實(shí)現(xiàn)子類以免無(wú)意中違反了里氏代換原則,如果一個(gè)函數(shù)不滿足里氏代換原則,那么它可能必須顯式地引用子類對(duì)象,這樣的函數(shù)同樣違反了開(kāi)閉原則,因?yàn)楫?dāng)添加新的子類時(shí),必須修改它。
考慮下面的矩形類:
// A very nice Rectangle class.public class Rectangle {private double width;private double height;public Rectangle(double w, double h) {width = w;height = h;}public double getWidth() {return width;}public double getHeight() {return height;}public void setWidth(double w) {width = w;}public void setHeight(double h) {height = h;}public double area() {return (width * height);}
現(xiàn)在,如果有個(gè)正方形呢?顯然正方形是一個(gè)矩形,所以我們應(yīng)該讓正方形繼承矩形類,是這樣嗎?我們看一下!
注意:
下面是Square類:
// A Square class.public class Square extends Rectangle {public Square(double s) {super(s, s);}public void setWidth(double w) {super.setWidth(w);super.setHeight(w);}public void setHeight(double h) {super.setHeight(h);super.setWidth(h);}}
一切看上去都很好,但是注意下面的代碼:
public class TestRectangle {// Define a method that takes a Rectangle reference.public static void testLSP(Rectangle r) {r.setWidth(4.0);r.setHeight(5.0);System.out.println("Width is 4.0 and Height is 5.0" +", so Area is " + r.area());if (r.area() == 20.0)System.out.println("Looking good!\n");elseSystem.out.println("Huh?? What kind of rectangle isthis??\n");}public static void main(String args[]) {// Create a Rectangle and a SquareRectangle r = new Rectangle(1.0, 1.0);Square s = new Square(1.0);// Now call the method above. According to the// LSP, it should work for either Rectangles or// Squares. Does it??testLSP(r);testLSP(s);}}
測(cè)試程序輸出:
Width is 4.0 and Height is 5.0, so Area is 20.0Looking good!Width is 4.0 and Height is 5.0, so Area is 25.0Huh?? What kind of rectangle is this??
看起來(lái)我們違反了里氏代換原則,問(wèn)題在哪兒?testLSP()方法合理的假設(shè)當(dāng)一個(gè)矩形的寬改變時(shí),它的高度不變。當(dāng)傳遞一個(gè)正方形對(duì)象時(shí),該方法卻違反了里氏代換原則。從數(shù)學(xué)上看,正方形是一個(gè)矩形,但是一個(gè)正方形對(duì)象卻不是矩形對(duì)象,因?yàn)橐粋€(gè)正方形對(duì)象的行為和一個(gè)矩形對(duì)象的行為不一致。從行為上來(lái)說(shuō),正方形不是矩形!里氏代換原則清晰的說(shuō)明,IS-A關(guān)系是對(duì)于所有的行為來(lái)說(shuō)的,為了遵循里氏代換原則,子類的行為必須和客戶端使用的基類的行為一致。
子類不能比基類具有更多的約束,因?yàn)楸仨氃谌魏慰梢允褂没惖牡胤绞褂米宇悾绻宇惐然愑懈嗟募s束,那么就會(huì)出現(xiàn)基類可用,但卻違反了子類約束的情況。
總結(jié)
里氏代換原則是對(duì)開(kāi)閉原則的擴(kuò)展,它表明我們?cè)趧?chuàng)建基類的新的子類時(shí),不應(yīng)該改變基類的行為。
聯(lián)系客服