HeadFirst 設計模式學習筆記7--適配器模式和外觀模式

1.適配器的作用:將一個接口轉換爲另一個接口。我們可以比喻爲一個插座的轉換頭。

2.構造適配器的關鍵:實現了目標接口,並持有被適配者的實例。 而適配器使用的方法是:客戶通過目標接口調用適配器的方法對適配器發出請求,適配器使用被適配者接口把請求轉換爲被支配者的一個或多個調用接口。我們舉一個火雞冒充鴨子的適配器例子:

我們定義兩個東西:

一個是鴨子:

一個是火雞:

我們現在做的就是要讓火雞有能力去冒充鴨子,那麼我們必須把火雞的一些能力映射到鴨子具備的一些能力中去,於是我們就採用了一個負責處理這樣映射的類——適配器類:

在這個類似於一種能力轉換器的類中,我們首先指定了我們向轉換爲Duck的能力(implements Duck),而這個能力的實際提供者——Turkey則被我們以成員變量的形式置於這個類內部(Turkey turkey;)並且在這個類生成對象時傳入(public TurkeyAdapter(Turkey turkey ) )。下一步就是具體定義這些能力的時候了——也就是把接口定義的方法都對應實現。

在使用的時候,我們的意圖是讓火雞冒充鴨子,那麼我們要先建立一個火雞,然後建立一個能力轉換器(new TurkeyAdapter(turkey)) ,把我們建立好的火雞傳進去處理,這樣得到的一個對象(turkeyAdapter )就可以完全當做一個鴨子使用了。

這樣的設計體現了良好的OO設計原則:使用對象組合,包裝被適配者。並且它是通過接口進行組合將二者綁定起來,而不是實現——這就是一個對象適配器的設計觀念。

3.而一個類適配器與對象適配器不同之處在於,類適配器使用繼承的方式,多重繼承了被適配者(此例中爲火雞)和目標適配者(此例中爲鴨子)兩者。而對象適配器則實現了鴨子的接口,在具體調用時則通過內部的火雞成員變量提供具體真實的能力,通過這樣的方式將兩者組合起來。通過對比,我們能得到如下一些特點:

對象適配器不但能適配某一個類,而且還可以適配該類的任意子類,另外實現的方法可以由多個方法搭配完成,這樣更具有彈性。

類適配器則只在需要的時候使用覆蓋來實現一些方法,而不用像對象適配器一樣實現整個被適配者的各種方法,因爲它可以直接使用繼承,更加有效率。

另外需要說明的是:由於Java中無法提供多重繼承,所以無法輕易實現類適配器這個層面的東西。

4.在Sun Java中一個實際使用適配器的例子就是Iterator接口,它實現了對集合類型的遍歷。

5.你可能發現一個事情:裝飾者模式和適配器模式貌似比較相像,我們做一下比較:

裝飾者需要有一些新的行爲或者職責要加入到設計中,並且動態的進行添加處理,而適配器模式則是需要將一個能力轉換爲另一個能力,靜態敲定了一些能力。裝飾者也可以做到能力轉換,而且還支持新行爲的加入,適配器只是裝飾者的一種變體,都是用來包裝對象的。而從另外的角度,適配器一定會對接口進行轉換,而裝飾者一定不會。從意圖上說,裝飾者是被改變接口而擴展包裝對象的行爲或者職責,而適配器則是爲了轉換包裝對象的行爲來改變接口。

6.你可能會覺得頭暈,但是我們現在要引入一個改變接口的新模式——外觀模式(facade),它改變接口的目的是簡化接口。外觀類沒有對子系統進行封裝,只是提供了集合式簡化的接口。這其實是一個極樸素的概念,不只是簡化了接口,也將客戶從組件的子系統中解耦出來。外觀和適配器都可以包裝多個類,但是外觀的意圖在於簡化接口,而適配器的意圖在於將接口轉換成不同的接口。書中舉了家庭影院的外觀模式例子,將許許多多的組件動作結合在一起完成了一系列對用戶來講方便的方法:

我們使用這個外觀模式就可以簡單舒適的看一場電影了:

我們最後給外觀模式一個定義:提供了一個統一的接口,用來訪問子系統中的一羣接口,外觀定義了一個高層接口,讓子系統更容易使用。

7.我們由此引入一個新的OO原則——最少知識(Least Knowledge)原則(也就是傳說中的Law of Demeter):只和你的密友談話。也就是說,當你正在設計一個系統時不管是任何對象,你都要注意它所交互的類有哪些,並注意它和這些類是如何交互的。儘量減少類之間的依賴。針對這個原則,我們有一系列的準則可以遵循:對於任何對象,在其內部的方法中,我們只應該調用屬於以下範圍的方法:

  • 該對象本身。
  • 被當做方法的參數而傳遞進來的對象。
  • 此方法所創建或實例化的任何對象。
  • 對象中的其他任何的對象成員和方法。

舉一個汽車的例子:

不要對某個調用其他方法返回的對象進行方法的調用,我們若是這麼做就相當於向另一個對象的子部分發請求,耦合性就會加大。但是這個原則也會帶來一些弊端,導致更多的“包裝”類被製造出來,以處理和其他組件的溝通,增加程序複雜度和運行時的性能。

我們再舉書中一個練習題的例子仔細看看這個相當基本且重要的原則:

一個不符合這個原則的案例:

這個getTemp方法中涉及了一個調用返回的對象。

而我們把這個方法拆開就可以得到一個符合這個原則的案例:

但是這有意義嗎?恐怕是沒有的。其實我們經常用到違反該原則的例子,比如System.out.println……,這就告訴我們這並非是金科玉律。有好有壞吧, 凡事有得有失,在外觀模式中,我們看到HomeTheaterFacade 類是遵循這個原則的,這就主要帶來好處:一個組件的更換和升級不影響我們通過HomeTheaterTestDrive這個測試類中的主函數去輕鬆的看一場電影。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章