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

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

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

    Sealyu

    --- 博客已遷移至: http://www.sealyu.com/blog

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      618 隨筆 :: 87 文章 :: 225 評論 :: 0 Trackbacks

    長方形和正方形

    正方形是否是長方形的子類的問題,西方一個很著名的思辨題。

    正確的寫法是:

    長方形類:兩個屬性,寬度和高度;正方形類:一個屬性,邊。

    (LY注:這是至少流行了十年的思辨題目,最早來自于C++和Smalltalk領域。類似的這種思辨問題還有哪些呢?讓我不禁對哲學又感冒起來了。查閱資料時意外找到了一個討論區,里面有讀者和作者關于此處的拓展討論,真讓人高興。)

    (LY注:書中沒有提契約即Design by Contract的概念。子類應當完全繼承父類的contract。《敏 捷軟件開發:原則、模式與實踐》一書中這樣寫,"基于契約設計(Design By Constract),簡稱DBC"這項技術對LISKOV代換原則提供了支持.該項技術Bertrand Meyer伯特蘭做過詳細的介紹:使用DBC,類的編寫者顯式地規定針對該類的契約.客戶代碼的編寫者可以通過該契約獲悉可以依賴的行為方式.契約是通過 每個方法聲明的前置條件(preconditions)和后置條件(postconditions)來指定的.要使一個方法得以執行,前置條件必須為真. 執行完畢后,該方法要保證后置條件為真.就是說,在重新聲明派生類中的例程(routine)時,只能使用相等或者更弱的前置條件來替換原始的前置條件, 只能使用相等或者更強的后置條件來替換原始的后置條件。  本書中長方形的Contract是width和height可以獨立變化,這個contract在正方形中被破壞了。)

    (LY注:注意,我們所有討論的基礎都應由類的行為決定。這使得長方形等類是動態的,而不是象現實生活中一樣是靜態的概念。)

     

    正方形不可以作為長方形的子類

    如果設定一個resize方法,一直增加長方形的寬度,直到增加到寬度超過高度才可以。

    那么如果針對子類正方形的對象調用resize方法,這個方法會導致正方形的邊不斷地增加下去,直到溢出為止。換言之,里氏法則被破壞掉了。

    這個例子很重要,它意味著里氏代換與通常的數學法則和生活常識有不可混淆的區別。

    (LY 注:常識認為,正方形is a 長方形,而且是一類特殊的長方形。但是在這里出了問題,如果我們系統中不會有這樣的resize操作,是否正方形就可以作為長方形的子類了呢?看后文是可以的)

    代碼的重構

    長方形和正方形到底應該是什么關系呢?

    它們應該都是四邊形類的子類。四邊形類中沒有賦值方法,因類似上文的resize()方法不可能適用于四邊形類,而只能只用于不同的具體子類長方形和正方形。因此里氏代換原則不會被破壞。(LY注:針對需要賦值操作的情況)

    從抽象類繼承

    應盡量從抽象類繼承,而不是從具體類繼承。

    上文對長方形和正方形的重構使用了重構的第一種方法。增加一個抽象類,讓兩個具體類都成為抽象類的子類。

    記住一條指導性的原則,如果有一個由繼承關系形成的等級結構的話,在等級結構樹圖上的所有樹葉節點都應當是具體類;而所有的樹枝節點都應當是抽象類或者Java接口。

    問答題

    1、  一個有名的思辨題,filename能不能作為string類的子類?

    答:不能。Filename對象不能實現string對象的所有行為。比如兩個string對象相加可以給出一個新的有效的string對象。而兩個filename對象相加未必會得到一個新的有效的Filename對象。

           另外,Java中的String類型是final類型,因此不可以繼承。

    2、  如果正方形的邊長不會發生改變,是否可以成為長方形的子類呢?(LY注:不變正方形,就是邊長不會發生變化的正方形,也就是遵守不變模式的正方形。不變(Immutable)模式,一個對象在對象在創建之后就不再變化。)

    答:可以。實現時,父類有兩個屬性寬度和高度。子類有三個屬性寬度、高度和邊。針對每一個屬性,包含一個內部變量,一個Set值方法,一個Get值方法。子類正方形只需要將Set值方法不寫任何語句即可。

    3、  從里式代換角度看JavaPropertiesHashtable的關系是否合適?

    答:不合適。在Java中,PropertiesHashtable的子類。顯然Properties是一種特殊的Hashtable,它只接受string類型的鍵(Key)和值(Value)。但是,父類Hashtable可以接受任何類型的鍵和值。這意味著,在一些需要非String類型的鍵和值的地方,Properties不能取代Hashtable

    (LY注:合成/聚合復用原則中有更詳細的討論,應使用合成/組合而不是繼承。它們是has a的關系而不是is a的關系。)




    另外,有一篇有意思的文章不贊同這個觀點:

    本文假定讀者已經了解有關正方形不是長方形的相關內容。
            
            之前人們討論的正方形長方形的問題的關鍵 在哪里?我覺得就在于改動長方形的邊的長度。我們可以這么考慮一下,一個長方形的instance的邊長應該是可變的嗎?我覺得一旦一個長方形的邊長改變 之后它就成了另一個長方形了(一個新的instance)。所以長方形類里面不應該有改變其邊長的方法,一個長方形實例各個的邊長應當在new它的時候確 定下來,并且它們應當是immutable的?;谶@種考慮,我設計的長方形和正方形的類如下所示:
    //長方形
    public class Rectangle {
      private final int width;
      private final int height;
     
      public Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
      }
     
      public int getWidth() {
        return width;
      }

      public int getHeight() {
        return height;
      }
     
      public int getArea() {
        return width*height;
      }
    }

    //正方形
    public class Square extends Rectangle{
      private final int side;
     
      public Square(int side) {
        super(side, side);
        this.side = side;
      }
     
      public int getSide() {
        return side;
      }
    }

            這種繼承關系就既符合現實中的父子關系也遵循LSP。之所以這么設計,我的想法是一個類所具有的方法不應當能夠改變其本質。比如有一個Men類,它可以有 eat(),sleep(),work(),makeLovewith(Person p)方法,但是如果你在里面定義denatureToWomen(),denatureToEunuch()就很不恰當了,因為這改變了其本質,導致這個 Men的實例不再屬于Men類(至少已經和現實不吻合)了。除非這兩個方法不能改變該實例本質,否則在Men里面定義這兩個方法本身就是有問題的。不過如 果用下面這種方式定義也許可行:
    public Women denatureToWomen() {
      Women w = new Women();
      //set attributes here
      return w;
    }

    public Eunuch denatureToEunuch() {
      Eunuch e = new Eunuch();
      //set attributes here
      return e;
    }

    這樣一來,調用denatureToWomen()會產生一個新的實例,原來的那個Men實例依然存在,這和現實生活依然不吻合,現實生活中一個實例不光可以上型(upcast),還可以平行型,寒。。。

    總之一句話,一個類的方法不應該改變其實例的本質。


    posted on 2009-12-23 15:39 seal 閱讀(2473) 評論(0)  編輯  收藏 所屬分類: 設計模式
    主站蜘蛛池模板: 最近免费字幕中文大全视频 | 免费观看男人吊女人视频| yellow视频免费看| 国产精品福利在线观看免费不卡| 久久99青青精品免费观看| 成年女人午夜毛片免费看| 亚洲婷婷国产精品电影人久久| 亚洲国产精品一区二区久久hs| 亚洲精品欧洲精品| 一级人做人a爰免费视频| 成人亚洲综合天堂| 911精品国产亚洲日本美国韩国 | 亚洲精品国产肉丝袜久久| 蜜臀98精品国产免费观看| 亚洲国产成人久久一区WWW| 亚洲精品美女久久久久9999| 亚洲高清免费在线观看| 中国亚洲呦女专区| 两个人看的www免费视频中文| 女性自慰aⅴ片高清免费| 亚洲综合伊人久久大杳蕉| 精品国产成人亚洲午夜福利| 日韩特黄特色大片免费视频| 亚洲精品二区国产综合野狼| 人人爽人人爽人人片A免费| 亚洲免费综合色在线视频| 日本亚洲欧洲免费天堂午夜看片女人员| 花蝴蝶免费视频在线观看高清版| 亚洲AⅤ无码一区二区三区在线| 巨胸狂喷奶水视频www网站免费| 免费国产综合视频在线看| 亚洲日本乱码卡2卡3卡新区| 成人午夜性A级毛片免费| 日本中文字幕免费看| 亚洲无删减国产精品一区| 韩国免费A级毛片久久| 色拍自拍亚洲综合图区| 日本免费人成视频在线观看| 亚洲国产AV无码专区亚洲AV| 和日本免费不卡在线v| 亚洲一级大黄大色毛片|