面向對象設計之LSP
??????前段時間完成我的畢業論文,是關于面向對象設計原則和設計模式的一些討論,為此重讀了Robert C.Martin的《Aglile Software Development Principles,Patterns and Pratices》這本著作,對面向對象設計有了一個新的認識,在這里和大家分享一下。
??????《Agile》一書中提到一系列的面向對象設計原則,其中一條是叫作LSP---Liskov替換原則。LSP是Barbara Liskov在她1988年的論文中提出的,其內容是:子類必須能夠完全替換掉它的父類。LSP是使OCP成立的條件之一(關于OCP在以后的文章會作討論),二者都是面向對象的多態和抽象的基礎。
??????舉個例子,當我們有一個Car這個類
public
?
class
?Car?{
????
???? public ? void ?run(){
????????System.out.println( " I?am?running " );
????}
????
???? public ? void ?stop(){
????????System.out.println( " I?am?stop " );
????}
}
????
???? public ? void ?run(){
????????System.out.println( " I?am?running " );
????}
????
???? public ? void ?stop(){
????????System.out.println( " I?am?stop " );
????}
}
現在,如果有一個類與Car類有關系,在面向對象中,類之間的關系就是組合和繼承。當確定這個類為另外一個類的使用者、擁有者時就用組合,譬如Person類使用Car類。使用者的類有一個特征就是運行時多態放在它們之間是不管用的,譬如Person可能有一些eat、laugh等公共方法,如果Person是Car的子類,根據運行時多態就可以用Car來替換Person,Car就有得eat這個方法,顯然是不合邏輯的。
??? 如果確定是有一種特殊的Car會飛的,除了run和stop之外還有一個fly的方法,現在就是使用繼承的場合。
public?class?FlyingCar?extends?Car?{
????public?void?fly(){
????????System.out.println("I?am?Fly");
????}
}
????public?void?fly(){
????????System.out.println("I?am?Fly");
????}
}
雖然使用了繼承,但是確違反了LSP。因為Car中并沒有fly這個方法,運行時多態便被破壞。為了獲得多態性,將Car重構為抽象類,在其中添加一個抽象的fly方法,多態性便得以保存。但是這樣做的話就說明所有Car的抽象都是會fly的,這顯然是不合理。為此,應該去掉Car中的fly方法,Car就不是抽象類,再由Car這個抽象類派生出抽象的FlyingCar,里面包含fly的抽象方法。這樣,FlyingCar抽象類和它的派生類就確保遵守了LSP了。
??????還有一種做法,將fly方法抽象到一個Flyable接口中。FlyingCar在繼承Car的同時實現Flyable接口,就是說,FlyingCar的上級父類就是Car和Flyable,按照LSP是完全可以覆蓋父類的。
public?interface?Flyable?{
????void?fly();
}
????void?fly();
}
public?class?FlyingCar?extends?Car?implements?Flyable?{
????public?void?fly(){
????????System.out.println("I?am?fly");
????}
}
????public?void?fly(){
????????System.out.println("I?am?fly");
????}
}
使用運行時多態時要獲得fly方法必須轉型為Flyable接口
public?class?CarMain?{
????public?static?void?main(String[]?args)?{
????????Car?car=new?FlyingCar();
????????car.run();
????????car.stop();
????????((Flyable)car).fly();
????}
}
????public?static?void?main(String[]?args)?{
????????Car?car=new?FlyingCar();
????????car.run();
????????car.stop();
????????((Flyable)car).fly();
????}
}
LSP是指導使用繼承的準則。繼承肯定是子類添加父類所不具有的新方法的,此時若忽略LSP,多態性便會在設計中消失。所以當使用繼承時,為了保證多態性,就需要遵守LSP多做一些工作了。
posted on 2006-08-03 00:28 it民工 閱讀(775) 評論(1) 編輯 收藏 所屬分類: 面向對象思想