zxbyhcsdn

           

          正方形是否是長方形的子類?

           

          長方形和正方形

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

          正確的寫法是:

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

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

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

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

           

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

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

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

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

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

          代碼的重構(gòu)

          長方形和正方形到底應(yīng)該是什么關(guān)系呢?

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

          從抽象類繼承

          應(yīng)盡量從抽象類繼承,而不是從具體類繼承。

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

          記住一條指導(dǎo)性的原則,如果有一個由繼承關(guān)系形成的等級結(jié)構(gòu)的話,在等級結(jié)構(gòu)樹圖上的所有樹葉節(jié)點(diǎn)都應(yīng)當(dāng)是具體類;而所有的樹枝節(jié)點(diǎn)都應(yīng)當(dāng)是抽象類或者Java接口。

          問答題

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

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

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

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

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

          3、  從里式代換角度看JavaPropertiesHashtable的關(guān)系是否合適?

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

          (LY注:合成/聚合復(fù)用原則中有更詳細(xì)的討論,應(yīng)使用合成/組合而不是繼承。它們是has a的關(guān)系而不是is a的關(guān)系。)

          posted on 2009-11-26 21:50 zxbyh 閱讀(1537) 評論(0)  編輯  收藏 所屬分類: OOAD

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 克山县| 西乌珠穆沁旗| 修武县| 开封市| 始兴县| 松溪县| 巴南区| 襄汾县| 沙坪坝区| 朝阳市| 东乡县| 无棣县| 军事| 扶风县| 沙坪坝区| 乃东县| 宜君县| 凭祥市| 濮阳县| 阿拉善盟| 沙洋县| 班戈县| 建始县| 依安县| 玛纳斯县| 博乐市| 永州市| 彭泽县| 吴忠市| 夹江县| 莱阳市| 临洮县| 吉林省| 沅江市| 同心县| 任丘市| 宁晋县| 五河县| 麻江县| 宁城县| 邯郸市|