<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      DesignPattern系列__04里氏替換原則

      1.內容引入——繼承體系的思考

      在繼承中,凡是在父類已經實現的方法,其實算是一種契約或者規范,子類不應該在進行更改(重寫);但是,由于這一點不是強制要求,所以當子類進行重寫的時候,就會對繼承體系產生破壞。
      同時,繼承帶來便利的時候,也有弊端:給程序帶來了侵入性,增加了對象之間的耦合性,可移植性低。當你修改基類時,子類都需要進行相應的修改。
      那么,如何能夠保持繼承的優點,同時減少缺點對程序的影響呢?也就是我們要討論的主角——“里氏替換原則”。

      2.里氏替換原則的定義

      1.第一種定義

      如果對每一個類型為S的對象o1, 都用類型為T的對象o2, 使得以T定義的所有程序P在所有的對象o1都替換為o2時,程序P的行為沒有發生變化,那么類型S是類型T的子類型。

      2.第二種定義

      所有引用基類的地方都必須能透明地使用其子類進行替換。

      第二種類型通俗易懂,就是說,只要父類出現的地方,都應該能用其子類進行替換。 但是反過來卻不一定成立,也就是子類所在的地方替換成父類,是不一定成立的。

      根據定義,我們總結出以下幾點:

      1.子類必須實現父類定義的抽象方法。對于父類已經實現的非抽象方法,不應該進行重寫。

      結合代碼理解一下:

      public abstract class SuperClass {
          public abstract void sayHi();
          public void doSomething() {
              System.out.println("父類被執行...");
          }
          
          //定義一個加法運算函數
          public int add(int i, int j) {
              int result = i + j;
              System.out.println("result = " + result);
              return result;
          }
      }
      
      public class SubClass extends SuperClass {
          @Override
          public void sayHi() {
              System.out.println("子類重寫了父類的sayHi方法...");
          }
      
          //子類特有的方法
          public void selfMethod() {
              System.out.println("子類特有的方法");
          }
      
          //子類重寫了父類的非抽象加法運算方法
          @Override
          public int add(int i, int j) {
              int result = i - j;
              System.out.println("result = " + result);
              return result;
          }
      
      }
      
      public class Client {
          public static void main(String[] args) {
              SuperClass clazz = new SubClass();
              clazz.doSomething();
              SubClass subClass = new SubClass();
              //子類調用自己的方法
              subClass.selfMethod();
              SuperClass superClass = (SuperClass) subClass;
              superClass.add(11,22);
          }
      }
      
      //運行結果如下:
      父類被執行...
      子類特有的方法
      result = -11
      

      當你繼承一個基類時,編譯器會要求你來實現基類的抽象方法,否則,會報錯。
      但是,對于已經實現的方法,編譯器便不會強制讓你去重寫(也不推薦這樣做):在上面的demo中,子類重寫了父類的add方法,在調用時,出現了錯誤(基類定義的加法邏輯,被子類重寫為了一個減法)。這樣子,在父類出現的地方,不能由子類完全替換,違背了“里氏替換原則”。

      2.子類可以有自己的方法。

      在上面的demo中,子類定義了特有的方法selfMethod(),可以實現其他的業務邏輯。

         //子類特有的方法
          public void selfMethod() {
              System.out.println("子類特有的方法");
          }
      

      3.當子類覆蓋或實現父類的方法時,前置條件(形參)可以比父類方法的輸入參數更寬松。

      下來看一下demo:

      public class Father {
          public Collection doSomething(HashMap map) {
              System.out.println("父類被執行...");
              return map.values();
          }
      }
      
      public class Son extends Father {
           public Collection doSomething(Map map) {
              System.out.println("子類被執行...");
              return map.values();
          }
      }
      
      public class Client1 {
          public static void main(String[] args) {
              invoke();
          }
      
          public static void invoke() {
      //        Father clazz = new Father();
              Son clazz = new Son();
              HashMap hashMap = new HashMap();
              clazz.doSothing(hashMap);
          }
      
      //運行結果:父類執行...
      

      在demo中,基類定義了一個doSomething方法,接受的形參類型為HashMap,子類重載了基類的這個方法,并且將接受的形參類型擴展為Map。但是,我們發現,在父類出現的地方,替換為子類后,運行的結果不變。也就是說,子類對象在方法執行時被替換為父類對象,重載的方法并未被執行。如果想要執行子類的方法,就必須重寫,這是正確的。
      如果反過來呢?下面通過反證來證明第三點:
      當子類的方法中的前置條件比父類小的時候,情況會怎么樣呢?
      在父類和子類中重新定義這兩個方法,符合子類的前置條件小于父類這一條件即可。

         //修改父類的方法,前置條件擴大為Map
          public Collection doSomething(Map map) {
              System.out.println("父類被執行...");
              return map.values();
          }
      
         //修改子類,前置條件縮小為HashMap
          public Collection doSomething(HashMap map) {
              System.out.println("子類被執行...");
              return map.values();
          }
      

      當客戶端的invoke()方法中,通過Father類型調用doSomething方法時,運行結果如下:
      //運行結果: 父類執行****
      將對象換成Son類型時,執行結果時:

       public static void invoke() {
      //        Father clazz = new Father();
              Son clazz = new Son();
              HashMap hashMap = new HashMap();
              clazz.doSothing(hashMap);
          }
      
      //執行結果: 子類被執行...
      

      我們看到了,子類并沒有重寫父類的方法,但是子類的方法被執行了(這是因為調用方法時,優先選擇參數類型一致的方法,也就是重載方法,找不到的話才去找類型為形參的基類的方法),但是,這個現象在邏輯上面是錯誤的。

      4.當子類的方法實現父類的抽象方法時,方法的后置條件(即方法的返回值)要比父類更嚴格。

      這一點是重寫的要求之一,在這里就用代碼展示了。

      最佳實踐

      在前面的示例中,我們在子類SubClass中不小心重寫了基類SupClass已經實現的方法add(),導致出現了邏輯錯誤。

      1.在實際的使用中,我們要盡量避免重寫父類已經實現的方法。

      2.在適當的情況下減少使用繼承,多使用聚合、組合、依賴等解決問題。

      posted @ 2019-08-05 11:23  本墨  閱讀(278)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 日韩有码av中文字幕| 成人午夜av在线播放| 亚洲特黄色片一区二区三区| 亚洲国产精品乱码一区二区| 临沭县| 无遮挡aaaaa大片免费看| 华人在线亚洲欧美精品| 中文字幕av一区二区三区人妻少妇| 377P欧洲日本亚洲大胆| 极品无码国模国产在线观看| 久久久一本精品99久久精品88 | 丰满人妻熟妇乱又伦精品劲| 又湿又紧又大又爽A视频男| 久久精品国产一区二区蜜芽| 欧美成人午夜精品免费福利| 亚洲天堂网中文在线资源| 国产午夜亚洲精品一区| 99国产精品久久久久久久日本竹| 农安县| 国产白嫩护士被弄高潮| 国产天美传媒性色av高清| 成人无码视频在线观看免费播放| 江永县| 中国性欧美videofree精品| 国产成人精品白浆免费视频试看| 日本一道一区二区视频| 国产一区二区不卡在线| 国产毛片基地| 98日韩精品人妻一二区| 午夜男女爽爽影院免费视频下载| 国产成人高清亚洲综合| 亚洲丰满熟女一区二区蜜桃| 国产精品男女午夜福利片| 国产激情av一区二区三区| 一本大道久久香蕉成人网| 久久精品国产九一九九九| 婷婷久久香蕉五月综合加勒比| 久久久久久毛片免费播放 | 成人片黄网站a毛片免费| 男女一级国产片免费视频| 国产一级精品在线免费看|