[學習筆記]設計模式之Adapter

寫在前面

爲方便讀者,本文已添加至索引html

Adapter(適配器)模式主要解決接口不匹配的問題。爲此,讓咱們要回到最初Builder模式建立平行世界時,白雪公主和小霍比特人的謎之相遇。在這個世界裏,咱們暫時有見到兩個種族Human和Hobbit。種族不一樣所產生的最大區別是什麼?固然個頭是一部分,也僅僅是一部分而已。畢竟Human裏也有怎麼長都才那麼高的吧:P。這裏要說的區別是:他們的語言不通。是的,白雪公主一開始根本就聽不懂小霍比特人在說什麼。設計模式

在這個平行世界中,全部的Human通用語是中文,(爲何是中文!由於全世界都在學中國話。)包括白雪公主(你知道我是必定不會忠於原著的)。而霍比特人,咱們假定他們用的是霍比特語。因此你們在表達「打招呼」的意思時,用的是徹底不一樣的語言:學習

 1 class Human {
 2 public:
 3     // ... other action ...
 4     virtual void hello() { cout << "你好!" << endl; }
 5 }
 6 
 7 class Hobbit {
 8 public:
 9     // ... other action ...
10     virtual void hohobi() { cout << "HOhoBI*" << endl; }
11 }

那後來白雪公主又是怎麼與小霍比特人們幸福快樂地生活在一塊兒了呢?這裏要提的是7個小霍比特人中,有一位博學的老者theWise,他曾在人類社會中生活了大半輩子,他曾任職於『跨種族文化研究協會』Cross-Racial Culture(CRC)。那段難忘的研究經歷讓他對Human的文化也是至關熟悉:ui

1 class CRC: public Human, public Hobbit {
2 public:
3     // ... other action ...    
4     virtual void hohobi() { hello(); }
5 }

能夠看到,CRC其實就是一個適配器,更具體的說,是類適配器。(適配器模式有兩種版本:類適配器對象適配器,下文會講到)它使用多重繼承對一個接口與另外一個接口進行匹配,見示例部分的說明。你們能夠想一想現實生活中,咱們是否是還見過許多相似適配器的設計?讓咱們來看看適配器模式的相關要點。spa

要點梳理

  • 目的分類
    • 類對象結構型模式
  • 範圍準則
    • 對象(該模式處理對象間的關係,這些關係在運行時刻是能夠變化的,更具動態性)
    • 類(該模式處理類和子類之間的關係,這些關係經過繼承創建,是靜態的,在編譯時刻便肯定下來了)
  • 主要功能
    • 將一個類的接口轉換成客戶但願的另一個接口。Adapter模式使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠一塊兒工做
  • 適用狀況
    • 咱們想使用一個已經存在的類,而它的接口不符合咱們的需求
    • 咱們想建立一個能夠複用的類,該類能夠與其餘不相關的類或不可預見的類(即那些接口設計

      可能不必定兼容的類)協同工做
  • 參與部分
    • Target:定義Client使用的與特定領域相關的接口
    • Client:與符合Target接口的對象協同
    • Adaptee:定義一個已經存在的接口,這個接口須要適配
    • Adapter:對Adaptee的接口與Target接口進行適配
  • 協做過程
    •  ClientAdapter實例上調用一些操做。接着適配器調用Adaptee的操做實現這個請求
  • UML圖

類適配器指針

對象適配器code

示例分析 - 跨越語言的障礙

當美麗的白雪公主遇到一個可愛的小霍比特人時,她向他打招呼:htm

1 Human theWhitePrincess = new Human();
2 Hobbit theLovely = new Hobbit();
3 theWhitePrincess.hello(); //你好!

可是小霍比特人理解不了。在他的世界裏,hohobi()纔是打招呼的方式。而Human是沒有hohobi()的,因而白雪公主溝通陷入了尷尬的狀態。好在theWise及時的來了:對象

1 Hobbit theWise = new CRC();
2 theWise.hohobi(); //你好!

因而白雪公主和其餘小霍比特人經過theWise都能互相理解了。借用下面這個圖咱們能夠理解下:

跨種族文化研究協會就是爲了實現種族之間文化交流溝通沒有障礙而生。它在這個場景下,就起到了適配器的做用,經過將Hobbit人打招呼的接口hobbit()轉化成Human打招呼的接口hello進行輸出。

可是世界的創造者時の魔導士也注意到了這件事。他並不但願之後的日子裏,白雪公主都要在theWise的陪同下才能與其餘人溝通,太不方便了對不對。因而他採用了童話世界裏最常出現的謎之物:霍比特仙果:一個能吃了後能讓人類得到理解霍比特人的神奇果實。從本質上來看,吃過果子後,屬於新的類別:HumanPlus

1 class HumanPlus : public Human {
2 public:
3     // ... other action ...
4     virtual void hello() { _hobbitSprite->hohobi(); }
5 private:
6     Hobbit* _hobbitSprite;
7 }

它的最大特點是,本身維護了一個Hobbit類的指針。利用_hobbitSprite對象達到適配器的目的,這就是另外一種對象適配器的模式。讓咱們來看圖:

總之,白雪公主順利地融入到小霍比特人的生活中。

特色總結

在此,咱們能夠總結下類適配器對象適配器各自的特色:

  1. 類適配器用一個具體的Adapter類對Adaptee和Target進行匹配。但如此一來,類Adapter將不能匹配Adaptee類的全部子類了。
  2. 對於類適配器,Adapter類是Adaptee類的子類,所以能夠重定義Adaptee類的部分行爲。
  3. 對於類適配器,僅僅引入一個對象,並不須要額外的指針以間接獲得adaptee
  4. 對象適配器則容許一個Adapter與多個Adaptee同時工做,它也能夠一次給全部的Adaptee添加額外的功能。
  5. 對於對象適配器,重定義Adaptee的行爲自己比較困難。

咱們須要注意的一些問題:

  1. 對Adaptee的接口與Target的接口進行匹配的工做量各個Adapter可能不同,主要取決於Target接口與Adaptee接口的類似程度。
  2. 當其餘的類使用一個類時,若是所需的假定條件越少,這個類就更具可複用性。若是將接口匹配構建爲一個類,就不須要假定對其餘的類可見的是一個相同的接口。也就是說,接口匹配使得咱們能夠將本身的類加入到一些現有的系統中去,而這些系統對這個類的接口可能會有所不一樣。
  3. 使用適配器的一個潛在問題是,它們不對全部的客戶都透明。被適配的對象再也不兼容Adaptee的接口,所以並非全部Adaptee對象能夠被使用的。這種狀況下,一個雙向的適配器就頗有必要了。通常可使用多重繼承來實現這一目的,尤爲是兩個類接口差別程度較大時。

寫在最後

今天的筆記就到這裏了,歡迎你們批評指正!若是以爲能夠的話,好文推薦一下,我會很是感謝的!

相關文章
相關標籤/搜索