《第1章設(shè)計模式入門》隨想

這一章在討論的問題

Using inheritance hasn't worked out very well, since the duck behavior keeps changing across the subclasses, and it's not appropriate for all subclasses to have those behaviors.

swim()quack()方法的討論

鴨子分為兩類,一類是生物鴨子,一類是模擬鴨子。

情況一

假設(shè)生物鴨子的swim()quack()方法都是一樣的;
假設(shè)模擬鴨子的swim()quack()方法都是特殊的。
那么相應的類圖如下:

鴨子有兩個抽象子類

Duck中的swim()quack()都是抽象方法。

情況二

假設(shè)生物鴨子的swim()quack()方法都是一樣的;
假設(shè)一部分模擬鴨子的swim()quack()方法跟生物鴨子一樣,一部分是特殊的。
如何重用鴨子中的swim()quack()方法?是不是要把swim()quack()的實現(xiàn)放到一個類中呢?

如果模擬鴨子的`swim()`和`quack()`方法跟生物鴨子一樣就繼承`AbtractCommonDuck`,否則繼承`Duck`

所有的生物鴨子都繼承AbtractCommonDuck,如果模擬鴨子的swim()quack()方法跟生物鴨子一樣就繼承AbtractCommonDuck,否則繼承Duck

情況三

假設(shè)鴨子的swim()quack()方法都是一樣的;
假設(shè)模擬鴨子的swim()quack()方法都是一樣的,但是跟鴨子的不一樣。
那么相應的類圖如下:

兩個子類有各自的實現(xiàn)

總結(jié)

假設(shè)生物鴨子swim()quack()方法也是有特殊情況的話,那么模擬鴨子和鴨子的組合就有很多種情況了,但是我是不會因為要重用swim()quack()這個兩個方法就把類圖搞得亂七八糟的,對于我來說,類圖就應該這樣設(shè)計:

只分鴨子和模擬鴨子子類

為什么要這樣?因為鴨子就是這樣分類的,軟件是在模擬現(xiàn)實,而且這樣的分類對大家來說都是通俗易懂的。
對于swim()quack()方法的具體實現(xiàn)我會放在Duck,或者是兩個子類中。
對于書中的只有Duck類也是可以的,即不區(qū)分生物鴨子和模擬鴨子:
所有的鴨子都是鴨子

fly()quack()方法的討論

在父類Duck中添加fly方法本身就是不適合的。我們必須明確飛行能力并非所有鴨子都有,比如橡皮鴨子就不具有飛行能力,所以把fly()放在父類中是否合適就很值得商榷。

`Duck`中只有共用的方法,其他的方法子類通過實現(xiàn)接口來實現(xiàn)

是否要把fly()quack()加入Duck?

可是加進去之后如果以后鴨子的行為有增加或刪除,那么這個類體系中的所有類都要進行修改。 ,以下是書中

所有的鴨子都是鴨子

大家覺得合適嗎?明明有些鴨子沒有飛行的能力,你卻給它加入了飛行的能力。
我認為可以從幾個角度進行思考:
1.這是一款鴨子應用,不管有多少種鴨子,都不會突然冒出一只雞;用戶、系統(tǒng)所應對的都是鴨子,沒有其他任何東西,這對于該系統(tǒng)來說是最簡單的;即使以后鴨子有了其他行為,比如跑步的方法,改起來是很痛苦的,但是對于系統(tǒng)和用戶來說,他們都只需要應付鴨子這個接口,無需理會其他事情。
2.這是一個很糟糕的設(shè)計,如果有新種類的鴨子加入,你就可能需要修改整個類體系,這跟一開始的做法有什么區(qū)別?但是問題是我擁有一只鴨子,我知道它能不能飛呢?我不知道,于是我這樣使用:

((FlyBehavior)duck).fly()

你喜歡這種方式嗎?你喜歡你的系統(tǒng)到處都需要進行這種檢查嗎?

到底是什么在變化?

鴨子的種類有很多,每種鴨子的行為是不可預測的。

這一章的內(nèi)容導讀

繼承——現(xiàn)在我們得讓鴨子能飛

在《但是,可怕的問題發(fā)生了》只是說明“對代碼所做的局部修改,影響層面可不只是局部”,“當涉及“維護”時,為了“復用”目的而使用繼承,結(jié)局并不完美”。
繼承的問題是必須確保父類中的實現(xiàn)對子類來說是合適的,所以必須仔細檢查從父類中繼承過來的行為是否是恰當?shù)摹?/p>

Joe想到繼承

繼承的缺點

這里使用繼承最大的缺點就是代碼在多個子類中重復

運行時的行為不容易改變倒不是什么大問題,因為一種鴨子的行為一般都是固定的,一個鴨子不可能會橫著飛又會豎著飛,難不成是鋼鐵俠?

改變會牽一發(fā)動全身,造成其他鴨子不想要的改變。由于實現(xiàn)是在父類中的,如果父類改變了它的實現(xiàn),所有繼承并沒有重寫該實現(xiàn)的鴨子都會受到波動,如果你不清楚有哪些子類沒有重寫該方法,那么就會有隱藏著的問題出現(xiàn)。

很難知道所有鴨子的全部行為

  • 這個真的不知道在說什么,使用策略模式就知道鴨子的全部行為了嗎?我想它的意思是如果我知道鴨子的全部行為的話,就可以跟我在《 對swim()quack()方法的討論》中討論的一樣,我們可以實現(xiàn)很多個抽象子類(就不會導致代碼在多個子類中重復),可惜我們不知道。或者是另外一個意思,我不知道鴨子的全部行為,所以我不能在父類中把這些行為都寫上,然后根據(jù)鴨子的種類判斷執(zhí)行那個操作。(說多都是淚,根本就看不懂。)
  • 第二種解釋是我不知道所有鴨子的全部行為,所以如果我改變了父類中的實現(xiàn),我不清楚會對哪些子類會產(chǎn)生影響。
  • 第三種解釋是我不清楚所有鴨子的全部行為,
    書中在說繼承的缺點,但是卻并不是說這樣設(shè)計類是不對的,Duck類是一定要包括所有種類的鴨子的行為的,而是說使用繼承,不能解決代碼重復的問題。

利用接口如何?

每當有新的鴨子子類出現(xiàn),他就要被迫檢查并可能需要覆蓋fly()和quark().....這簡直是無窮無盡的噩夢。

因為子類繼承了父類的行為,所以每個子類都必須好好檢查這些行為的實現(xiàn),如果不適當就必須進行修改,萬一忘記修改了,就會導致子類繼承了父類不恰當?shù)男袨椤?br>

使用接口

并非“所有”的子類都具有飛行和呱呱叫的行為,所以繼承并不是恰當?shù)慕鉀Q方式。

在父類中的實現(xiàn)會被子類繼承,如果子類沒有好好檢查并覆蓋父類中的方法,就可能會導致不恰當?shù)男袨楸焕^承下來。

針對接口編程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容