Scala學(xué)習(xí):使用組合與繼承
組合與繼承是利用其它現(xiàn)存類定義新類的兩個(gè)方法。如果你接下來(lái)的工作主要是代碼重用,通常你應(yīng)采用組合而不是繼承。只有繼承受脆基類問(wèn)題之苦,這種情況你可能會(huì)無(wú)意中通過(guò)改變超類而破壞了子類。
51CTO編輯推薦:Scala編程語(yǔ)言專題
關(guān)于繼承關(guān)系你可以問(wèn)自己一個(gè)問(wèn)題,是否它建模了一個(gè)is-a關(guān)系。Meyers,《Effective C++》 【Mey91】例如,說(shuō)ArrayElement是Element是合理的。你能問(wèn)的另一個(gè)問(wèn)題是,是否客戶想要把子類類型當(dāng)作超類類型來(lái)用。Eckel,《Thinking in Java》【Eck98】在ArrayElement的例子里,我們的確期待客戶會(huì)想要把ArrayElement當(dāng)作Element使用。
如果你對(duì)展示在圖釋10.3的繼承關(guān)系問(wèn)了這些的問(wèn)題,那么是否感覺(jué)其中的任何關(guān)系有可疑嗎?尤其是,對(duì)你來(lái)說(shuō)LineElement是ArrayElement是否顯而易見(jiàn)呢?你是否認(rèn)為客戶會(huì)需要把LineElement當(dāng)作ArrayElement使用?實(shí)際上,我們把LineElement定義為ArrayElement主要是想重用ArrayElement的contents定義。因此或許把LineElement定義為Element的直接子類會(huì)更好一些,就像這樣:
前一個(gè)版本中,LineElement與ArrayElement有一個(gè)繼承關(guān)系,從那里繼承了contents。現(xiàn)在它與Array有一個(gè)組合關(guān)系:在它自己的contents字段中持有一個(gè)字串?dāng)?shù)組的引用。類ArrayElement也與Array有組合關(guān)系,因?yàn)樗膮?shù)化contents字段持有字串?dāng)?shù)組的引用。ArrayElement的代碼展示在第xx頁(yè)的代碼10.5中。其組合關(guān)系用一個(gè)菱形表現(xiàn)在類圖中,正如展示在第xx頁(yè)的圖釋10.1中那樣。有了LineElement的這個(gè)實(shí)現(xiàn),Element的繼承層級(jí)現(xiàn)在看上去如展示在圖釋10.4中那樣。
- class LineElement(s: String) extends Element {
- val contents = Array(s)
- override def width = s.length
- override def height = 1
- }
圖釋 10.4 修改了LineElement后的類層級(jí)
【相關(guān)閱讀】