<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ## 連載:面向對象葵花寶典:思想、技巧與實踐(32) - LSP原則 LSP是唯一一個以人名命名的設計原則,而且作者還是一個“女博士”?![](https://box.kancloud.cn/2016-01-19_569e21abc5518.gif) ============================================================= **LSP**,Liskov?substitution?principle,中文翻譯為“**里氏替換原則**”。 ? 這是面向對象原則中唯一一個以人名命名的原則,雖然Liskov在中國的知名度沒有UNIX的幾位巨匠(Kenneth?Thompson、Dennis?Ritchie)、GOF四人幫那么響亮,但查一下資料,你會發現其實Liskov也是非常牛的:2008年圖靈獎獲得者,歷史上第一個女性計算機博士學位獲得者。其詳細資料可以在維基百科上查閱:[http://en.wikipedia.org/wiki/Barbara_Liskov](http://en.wikipedia.org/wiki/Barbara_Liskov)? ? 言歸正傳,我們來看看LSP原則到底是怎么一回事。 LSP最原始的解釋當然來源于Liskov女士了,她在1987年的OOPSLA大會上提出了LSP原則,1988年,她將文章發表在ACM的SIGPLAN?Notices雜志上,其中詳細解釋了LSP原則: A?type?hierarchy?is?composed?of?subtypes?and?supertypes.?The?intuitive?idea?of?a?subtype?is?one?whose?objects?provide?all?the?behavior?of?objects?of?another?type?(the?supertype)?plus?something?extra.What?is?wanted?here?is?something?like?the?following?substitution?property:?If?for?each?object?o1?of?type?S?there?is?an?object?o2?of?type?T?such?that?for?all?programs?P?defined?in?terms?of?T,?the?behavior?of?P?is?unchanged?when?o1?is?substituted?for?o2?then?S?is?a?subtype?of?T. 英文比較長,看起來比較累,我們簡單的翻譯并歸納一下: 1)?**子類的對象提供了父類的所有行為**,且加上子類額外的一些東西(可以是功能,也可以是屬性); 2)?當程序基于父類實現時,**如果將子類替換父類而程序不需要修改**,則說明符合LSP原則 ? 雖然我們稍微翻譯和整理了一下,但實際上還是很拗口和難以理解。 幸好還有Martin大師也覺得這個不怎么通俗易懂,Robert?Martin在1996年為《C++?Reporter》寫了一篇題為《The?The?Liskov?Substitution?Principle》的文章,解釋如下: Functions?that?use?pointers?or?references?to?base?classes?must?be?able?to?use?objects?of?derived?classes?without?knowing?it. 翻譯一下就是:函數使用指向父類的指針或者引用時,必須能夠在不知道子類類型的情況下使用子類的對象。 ? Martin大師解釋了一下,相對容易理解多了。但Martin大師還不滿足,在2002年,Martin在他出版的《Agile???Software???Development???Principles???Patterns???and???Practices》一書中,又進一步簡化為: Subtypes???must???be???substitutable???for???their???base???types。 翻譯一下就是:子類必須能替換成它們的父類。 ? 經過Martin大師的兩次翻譯,我相信LSP原則本身已經解釋得比較容易理解了,但問題的關鍵是:如何滿足LSP原則?或者更通俗的講:什么情況下子類才能替換父類? ? 我們知道,對于調用者來說(Liskov解釋中提到的P),和父類交互無非就是兩部分:調用父類的方法、得到父類方法的輸出,中間的處理過程,P是無法知道的。 ? 也就是說,調用者和父類之間的聯系體現在兩方面:函數輸入,函數輸出。詳細如下圖: ?![](https://box.kancloud.cn/2016-01-20_569f5ccb01a50.jpg) 有了這個圖之后,如何做到LSP原則就清晰了: 1)?**子類必須實現或者繼承父類所有的公有函數**,否則調用者調用了一個父類中有的函數,而子類中沒有,運行時就會出錯; 2)?**子類每個函數的輸入參數必須和父類一樣**,否則調用父類的代碼不能調用子類; 3)?**子類每個函數的輸出**(返回值、修改全局變量、插入數據庫、發送網絡數據等)必須不比父類少,否則基于父類的輸出做的處理就沒法完成。 ? 有了這三條原則后,就可以很方便的判斷類設計是否符合LSP原則了。需要注意的是第3條的關鍵是“不比父類少”,也就是說可以比父類多,即:父類的輸出是子類輸出的子集。 ? 有的朋友看到這三條原則可能有點納悶:這三條原則一出,那子類還有什么區別哦,豈不都是一樣的實現了,那還會有不同的子類么? ? 其實如果仔細研究這三條原則,就會發現其中**只是約定了輸入輸出,而并沒有約束中間的處理過程**。例如:同樣一個寫數據庫的輸出,A類可以是讀取XML數據然后寫入數據庫,B類可以是從其它數據庫讀取數據然后本地的數據庫,C類可以是通過分析業務日志得到數據然后寫入數據庫。這3個類的處理過程都不一樣,但最后都寫入數據到數據庫了。 ? LSP原則最經典的例子就是“長方形和正方形”這個例子。從數學的角度來看,正方形是一種特殊的長方形,但從面向對象的角度來觀察,正方形并不能作為長方形的一個子類。原因在于對于長方形來說,設定了寬高后,面積?=?寬?*?高;但對于正方形來說,設定高同時就設定了寬,設定寬就同時設定了高,最后的面積并不是等于我們設定的?寬?*?高,而是等于最后一次設定的寬或者高的平方。 具體代碼樣例如下: Rectangle.java ~~~ package com.oo.java.principles.lsp; /** * 長方形 */ public class Rectangle { protected int _width; protected int _height; /** * 設定寬 * @param width */ public void setWidth(int width){ this._width = width; } /** * 設定高 * @param height */ public void setHeight(int height){ this._height = height; } /** * 獲取面積 * @return */ public int getArea(){ return this._width * this._height; } } ~~~ Square.java ~~~ package com.oo.java.principles.lsp; /** * 正方形 */ public class Square extends Rectangle { /** * 設定“寬”,與長方形不同的是:設定了正方形的寬,同時就設定了正方形的高 */ public void setWidth(int width){ this._width = width; this._height = width; } /** * 設定“高”,與長方形不同的是:設定了正方形的高,同時就設定了正方形的寬 */ public void setHeight(int height){ this._width = height; this._height = height; } } ~~~ UnitTester.java ~~~ package com.oo.java.principles.lsp; public class UnitTester { public static void main(String[] args){ Rectangle rectangle = new Rectangle(); rectangle.setWidth(4); rectangle.setHeight(5); //如下assert判斷為true assert( rectangle.getArea() == 20); rectangle = new Square(); rectangle.setWidth(4); rectangle.setHeight(5); //<span style="color:#ff0000;">如下assert判斷為false,斷言失敗,拋出java.lang.AssertionError</span> assert( rectangle.getArea() == 20); } } ~~~ 上面這個樣例同時也給出了一個判斷子類是否符合LSP的取巧的方法,即:針對父類的單元測試用例,傳入子類是否也能夠測試通過。如果測試能夠通過,則說明符合LSP原則,否則就說明不符合LSP原則
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看