iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 3
1
自我挑戰組

來讀設計模式:Junior developer 跟大家一起練功系列 第 7

DAY7: Adapter 模式

上一篇,我介紹了 Facade 模式,今天我們繼續介紹另一個設計模式 —— Adapter 模式

Adapter 模式想解決的問題

先給出一個情境

假設客戶給出以下需求:

  • 將有 displayundisplay 行為的點、線、正方形分別建立類別;
  • 客戶不需要知道自己到底有點、線還是正方形。他只需知道他擁有這些形狀中的一個。

那麼,我們在這個時候會希望使用多型 —— 具有同樣的 method(display, undisplay),在不同物件會有不同的行為。但是客戶與他們的對話會是共同的。若以 UML 圖來看,會如同下圖:

這樣子,在我們的 Client 眼中,他互動的是 Shape,不需要去知道自己有的是哪一種形狀。

問題發生了!

今天,客戶需求增加了,客戶需要有個圓形,而且它也需要有 displayundisplay 兩種行為。

然而,你發現你同事在開發其他功能的時候,已經實作了一個名叫 MyCircle 類別,而此類別中剛好有 showvanish 兩種 methods:他們所做的行為剛好就符合 displayundisplay 的需求。

可惜地是,這個 MyCircle 並沒有繼承於 Shape,意指上述的架構無法套用在 MyCircle 上。

你當然可以假裝沒看到我的圓,直接實作出你自己的 Circle 類別,但是這樣等於是出現兩組類似的程式碼在你的系統裡。

這樣子就不 DRY 了,這樣會很 WET

Adapter 模式如何解決

簡單地說

GoF 如此開示

(Adapter 模式)將一個類別的介面轉換成客戶希望的另一個介面。Adapter 模式使原本由於介面不相容而不能一起工作的類別可以一起工作。

意思就是,某類別的功能符合我們的需求,但是介面上不同於原本的設計,那麼我們就建立一個新介面重新包裝該類別。

回到問題,如何實踐呢?

那我們如何實作 Adapter 模式在上述的問題上呢?

其實很簡單,就是建立一個 Circle 物件,然後將 Circle 包含 MyCircle。再將往後發自 Circle 的請求都丟給 MyCircle 去實作。

用 UML 圖來看,就會如下圖所示。

我們用 java 來實作,就會如下:

class Circle extends Shape {
  ...
  private MyCircle myCircle;
  ...
  public Circle() {
  	myCircle = new MyCircle();
  }
  
  void public display() {
    myCircle.show();
  }
  void public undisplay() {
    myCircle.vanish();
  }
}

(終於有程式碼出現了,感動落淚)

如此一來,我們就能維持原本的架構:客戶不知道實際的形狀。Adapter 模式最常見的用途也就是在此 —— 維持多型。而有了 Adapter 模式,我們也不需要擔心原有類別的介面了,因為總是可以用 Adpter 模式來提供正確的介面。

Adapter 模式的關鍵特徵

項目 描述
意圖 使控制範圍外的原有物件與某個介面匹配
問題 系統資料、行為皆正確,只有介面不符。常用於必須從抽象類別衍生時
解決方案 提供具有所需介面的 wrapper(包裝)類別
參與者與協作者 Adapter 改變了 Adaptee 的介面,使 Adaptee 與 Adapter 的父類別 Target 匹配。如此 Client 就可以使用 Adaptee 了,好像它是 Target 類型。
效果 使原有物件能夠適應新的類別結構,不受介面的限制
實作 把原有類別包含在另一個類別中。讓包含類別與需要的介面匹配。呼叫被複合類別的方法

下圖為 Adapter 模式的 UML 圖:

Adapter 模式有兩種類型

實際上 Adapter 模式有兩種類型:

  • 物件 Adapter 模式:相依於一個物件包含另一個物件(如前例)
  • 類別 Adapter 模式:透過多重繼承實現。

類別 Adapter 模式的實現方法是建立新類別,該類別同時從兩種類別繼承

  • 從定義其介面的抽象類別公開繼承
  • 從存取其實作的原有類別私有繼承

Adapter 模式與 Facade 模式

兩模式的差異如下表:

Facade 模式 Adapter 模式
是否存在既有的類別?
是否需要依某個介面設計?
物件是否需要多型行為? 可能
需要更簡單的見面嗎?

簡言之,Facade 模式簡化了介面;Adapter 模式則將一個介面轉成另一個介面。

接下來

接下來 cover 的是第八章。我們將會再從介紹設計模式跳出來,再回頭討論一下物件導向設計,並且引進新的觀點。

雖然好像又有點偏離主題(設計模式),但我認為這是很精彩的一章,這一章讓我重新看待了很多原本在物件導向中習以為常的事。所以我還是希望花點篇幅討論一下。

那麼明天見囉!


上一篇
DAY6: Facade 模式
下一篇
DAY8: 用不同觀點看物件與封裝
系列文
來讀設計模式:Junior developer 跟大家一起練功22

尚未有邦友留言

立即登入留言