<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    GHawk

    敏捷軟件開發(fā) 讀書筆記 (4)——OO五大原則(3.LSP——里氏替換原則)

    OCP作為OO的高層原則,主張使用“抽象(Abstraction)”和“多態(tài)(Polymorphism)”將設(shè)計(jì)中的靜態(tài)結(jié)構(gòu)改為動(dòng)態(tài)結(jié)構(gòu),維持設(shè)計(jì)的封閉性。

    “抽象”是語(yǔ)言提供的功能。“多態(tài)”由繼承語(yǔ)義實(shí)現(xiàn)。

    如此,問(wèn)題產(chǎn)生了:“我們?nèi)绾稳ザ攘坷^承關(guān)系的質(zhì)量?”

    Liskov于1987年提出了一個(gè)關(guān)于繼承的原則“Inheritance should ensure that any property proved about supertype objects also holds for subtype objects.”——“繼承必須確保超類所擁有的性質(zhì)在子類中仍然成立。”也就是說(shuō),當(dāng)一個(gè)子類的實(shí)例應(yīng)該能夠替換任何其超類的實(shí)例時(shí),它們之間才具有is-A關(guān)系。

    該原則稱為L(zhǎng)iskov Substitution Principle——里氏替換原則。林先生在上課時(shí)風(fēng)趣地稱之為“老鼠的兒子會(huì)打洞”。^_^

    我們來(lái)研究一下LSP的實(shí)質(zhì)。學(xué)習(xí)OO的時(shí)候,我們知道,一個(gè)對(duì)象是一組狀態(tài)和一系列行為的組合體。狀態(tài)是對(duì)象的內(nèi)在特性,行為是對(duì)象的外在特性。LSP所表述的就是在同一個(gè)繼承體系中的對(duì)象應(yīng)該有共同的行為特征。

    這一點(diǎn)上,表明了OO的繼承與日常生活中的繼承的本質(zhì)區(qū)別。舉一個(gè)例子:生物學(xué)的分類體系中把企鵝歸屬為鳥類。我們模仿這個(gè)體系,設(shè)計(jì)出這樣的類和關(guān)系。

     lsp-fig1.jpg

    類“鳥”中有個(gè)方法fly,企鵝自然也繼承了這個(gè)方法,可是企鵝不能飛阿,于是,我們?cè)谄簌Z的類中覆蓋了fly方法,告訴方法的調(diào)用者:企鵝是不會(huì)飛的。這完全符合常理。但是,這違反了LSP,企鵝是鳥的子類,可是企鵝卻不能飛!需要注意的是,此處的“鳥”已經(jīng)不再是生物學(xué)中的鳥了,它是軟件中的一個(gè)類、一個(gè)抽象。

    有人會(huì)說(shuō),企鵝不能飛很正常啊,而且這樣編寫代碼也能正常編譯,只要在使用這個(gè)類的客戶代碼中加一句判斷就行了。但是,這就是問(wèn)題所在!首先,客戶代碼和“企鵝”的代碼很有可能不是同時(shí)設(shè)計(jì)的,在當(dāng)今軟件外包一層又一層的開發(fā)模式下,你甚至根本不知道兩個(gè)模塊的原產(chǎn)地是哪里,也就談不上去修改客戶代碼了。客戶程序很可能是遺留系統(tǒng)的一部分,很可能已經(jīng)不再維護(hù),如果因?yàn)樵O(shè)計(jì)出這么一個(gè)“企鵝”而導(dǎo)致必須修改客戶代碼,誰(shuí)應(yīng)該承擔(dān)這部分責(zé)任呢?(大概是上帝吧,誰(shuí)叫他讓“企鵝”不能飛的。^_^)“修改客戶代碼”直接違反了OCP,這就是OCP的重要性。違反LSP將使既有的設(shè)計(jì)不能封閉!

    修正后的設(shè)計(jì)如下:

     lsp-fig2.jpg

    但是,這就是LSP的全部了么?書中給了一個(gè)經(jīng)典的例子,這又是一個(gè)不符合常理的例子:正方形不是一個(gè)長(zhǎng)方形。這個(gè)悖論的詳細(xì)內(nèi)容能在網(wǎng)上找到,我就不多廢話了。

    LSP并沒(méi)有提供解決這個(gè)問(wèn)題的方案,而只是提出了這么一個(gè)問(wèn)題。

    于是,工程師們開始關(guān)注如何確保對(duì)象的行為。1988年,B. Meyer提出了Design by Contract(契約式設(shè)計(jì))理論。DbC從形式化方法中借鑒了一套確保對(duì)象行為和自身狀態(tài)的方法,其基本概念很簡(jiǎn)單:

    1. 每個(gè)方法調(diào)用之前,該方法應(yīng)該校驗(yàn)傳入?yún)?shù)的正確性,只有正確才能執(zhí)行該方法,否則認(rèn)為調(diào)用方違反契約,不予執(zhí)行。這稱為前置條件(Pre-condition)。
    2. 一旦通過(guò)前置條件的校驗(yàn),方法必須執(zhí)行,并且必須確保執(zhí)行結(jié)果符合契約,這稱之為后置條件(Post-condition)。
    3. 對(duì)象本身有一套對(duì)自身狀態(tài)進(jìn)行校驗(yàn)的檢查條件,以確保該對(duì)象的本質(zhì)不發(fā)生改變,這稱之為不變式(Invariant)。

    以上是單個(gè)對(duì)象的約束條件。為了滿足LSP,當(dāng)存在繼承關(guān)系時(shí),子類中方法的前置條件必須與超類中被覆蓋的方法的前置條件相同或者更寬松;而子類中方法的后置條件必須與超類中被覆蓋的方法的后置條件相同或者更為嚴(yán)格。

    一些OO語(yǔ)言中的特性能夠說(shuō)明這一問(wèn)題:

    • 繼承并且覆蓋超類方法的時(shí)候,子類中的方法的可見性必須等于或者大于超類中的方法的可見性,子類中的方法所拋出的受檢異常只能是超類中對(duì)應(yīng)方法所拋出的受檢異常的子類。
      public class SuperClass{
          
      public void methodA() throws IOException{}
      }


      public class SubClassA extends SuperClass{
          
      //this overriding is illegal.
          private void methodA() throws Exception{}
      }


      public class SubClassB extends SuperClass{
          
      //this overriding is OK.
          public void methodA() throws FileNotFoundException{}
      }

    • 從Java5開始,子類中的方法的返回值也可以是對(duì)應(yīng)的超類方法的返回值的子類。這叫做“協(xié)變”(Covariant)
      public class SuperClass {
          
      public Number caculate(){
              
      return null;
          }

      }


      public class SubClass extends SuperClass{
          
      //only compiles in Java 5 or later.
          public Integer caculate(){
              
      return null;
          }

      }

    可以看出,以上這些特性都非常好地遵循了LSP。但是DbC呢?很遺憾,主流的面向?qū)ο笳Z(yǔ)言(不論是動(dòng)態(tài)語(yǔ)言還是靜態(tài)語(yǔ)言)還沒(méi)有加入對(duì)DbC的支持。但是隨著AOP概念的產(chǎn)生,相信不久DbC也將成為OO語(yǔ)言的一個(gè)重要特性之一。

    一些題外話:

    前一陣子《敲響OO時(shí)代的喪鐘》和《喪鐘為誰(shuí)而鳴》兩篇文章引來(lái)了無(wú)數(shù)議論。其中提到了不少OO語(yǔ)言的不足。事實(shí)上,遵從LSP和OCP,不管是靜態(tài)類型還是動(dòng)態(tài)類型系統(tǒng),只要是OO的設(shè)計(jì),就應(yīng)該對(duì)對(duì)象的行為有嚴(yán)格的約束。這個(gè)約束并不僅僅體現(xiàn)在方法簽名上,而是這個(gè)具體行為的本身。這才是LSP和DbC的真諦。從這一點(diǎn)來(lái)說(shuō)并不能說(shuō)明“萬(wàn)事萬(wàn)物皆對(duì)象”的動(dòng)態(tài)語(yǔ)言和“C++,Java”這種“按接口編程”語(yǔ)言的優(yōu)劣,兩類語(yǔ)言都有待于改進(jìn)。莊兄對(duì)DJ的設(shè)想倒是開始引入DbC的概念了。這一點(diǎn)還是非常值得期待的。^_^
    另外,接口的語(yǔ)義正被OCP、LSP、DbC這樣的概念不斷地強(qiáng)化,接口表達(dá)了對(duì)象行為之間的“契約”關(guān)系。而不是簡(jiǎn)單地作為一種實(shí)現(xiàn)多繼承的語(yǔ)法糖。

    posted on 2006-01-18 18:12 GHawk 閱讀(3973) 評(píng)論(2)  編輯  收藏 所屬分類: 軟件過(guò)程學(xué)習(xí)筆記

    評(píng)論

    # re: 敏捷軟件開發(fā) 讀書筆記 (4)——OO五大原則(3.LSP——里氏替換原則) 2006-01-19 11:08 zhouap

    生動(dòng),解釋得夠清晰  回復(fù)  更多評(píng)論   

    # re: 敏捷軟件開發(fā) 讀書筆記 (4)——OO五大原則(3.LSP——里氏替換原則) 2006-03-01 22:31 larry

    “林先生”??莫非是也是上海交大的??  回復(fù)  更多評(píng)論   

    主站蜘蛛池模板: 精品在线免费视频| a在线观看免费网址大全| 亚洲精品成人久久久| 免费看少妇高潮成人片| 亚洲国产情侣一区二区三区| 免费看美女被靠到爽的视频| a级片免费观看视频| 亚洲性无码AV中文字幕| 成人午夜亚洲精品无码网站| 一本岛高清v不卡免费一三区| 美女黄网站人色视频免费| 亚洲成AV人片在| 国产在线19禁免费观看国产 | 久久精品国产亚洲av天美18| 亚洲精品午夜无码专区| 性感美女视频免费网站午夜| 国产又黄又爽胸又大免费视频| 日本亚洲色大成网站www久久| 亚洲精品无码久久久影院相关影片| 野花高清在线观看免费完整版中文| 一区二区三区在线免费观看视频| 亚洲白嫩在线观看| 久久久久亚洲AV无码专区桃色| 大地资源免费更新在线播放 | 国产一级高清视频免费看| 精品无码无人网站免费视频| 美女黄频视频大全免费的| 亚洲一级毛片在线观| 亚洲精品成人网站在线观看| 国产乱人免费视频| 成人啪精品视频免费网站| 999任你躁在线精品免费不卡| 成人免费夜片在线观看| 亚洲精品天堂无码中文字幕| 亚洲精品国产手机| 亚洲AV本道一区二区三区四区| 亚洲精品动漫人成3d在线| 四虎影视大全免费入口| 999国内精品永久免费观看| 日本在线看片免费| 在线观看黄片免费入口不卡|