設計模式之適配器模式

2018-09-19 22:12:25ios

適配器模式

  適配器模式(Adapter):將一個類的接口轉換成客戶但願的另一個接口。Adapter模式使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠一塊兒工做。(注:C++  std的bind函數不就是作個的嗎)。適配器模式,就像是一個轉接頭,我只有三項插座,可是這個電器只有兩個插頭,那麼至於要在中間加一個轉接器,讓三項插座看起來是雙項插座,這樣就能使用了。它的做用就是「有個東西,已經在這裏了,你要使用它,可是又不能使用,短期內又不能改變它,那麼這個時候你就要想辦法去適配它」。所謂適配器就是使一個東西適合另外一個東西的東西。設計模式

什麼時候使用適配器

  在軟件開發中,系統的數據和行爲都正確,但接口不符合時,應該考慮適配器,目的是使控制範圍以外的一個原有對象與某個接口匹配。適配器模式主要適用於但願複用一些現存的類,可是接口又和複用環境不一致的環境。適配器模式分兩種:類適配器模式和對象適配器模式。類適配器模式經過多重繼承對一個接口與另外一個接口進行匹配。因此適配器模式的使用場景就是兩個類所作的事情相同或者類似,可是具備不一樣的接口是可使用它。這樣一來,客戶端代碼就能夠同一調用一個接口了。在雙方都不太容易修改接口的時候再使用適配器模式。ide

適配器模式UML圖

類適配器(UML):適配器核心Adapter直接繼承自Adaptee函數

對象適配器(UML):(核心Adapter和Adaptee是關聯關係)spa

Target:這是客戶端所期待的接口,目標能夠是具體的或者抽象的類,也能夠是接口(注:C++沒有接口的概念,但虛基類能夠替代接口的做用).net

Adapter:經過內部包裝一個Adaptee對象,把源接口轉換成目標接口。是適配器模式的核心,具備將Adaptee包裝成Target的職責。翻譯

Aadptee:須要適配的類設計

適配器的優缺點

本部分來自於博客:https://blog.csdn.net/liang19890820/article/details/669732963d

類適配器包含如下特色:code

  • 因爲 Adapter 直接繼承自 Adaptee 類,因此,在 Adapter 類中能夠對 Adaptee 類的方法進行重定義。
  • 若是在 Adaptee 中添加了一個抽象方法,那麼 Adapter 也要進行相應的改動,這樣就帶來高耦合。
  • 若是 Adaptee 還有其它子類,而在 Adapter 中想調用 Adaptee 其它子類的方法時,使用類適配器是沒法作到的。

對象適配器包含如下特色:

  • 有的時候,你會發現,去構造一個 Adaptee 類型的對象不是很容易。
  • 當 Adaptee 中添加新的抽象方法時,Adapter 類不須要作任何調整,也能正確的進行動做。
  • 可使用多態的方式在 Adapter 類中調用 Adaptee 類子類的方法。

因爲對象適配器的耦合度比較低,因此在不少的書中都建議使用對象適配器。

優勢:

  • 可讓任何兩個沒有關聯的類一塊兒運行
  • 提升了類的複用
  • 增長了類的透明度
  • 靈活性好

缺點:

  • 過多地使用適配器,會讓系統很是零亂,不利於總體把控。

例如,看到調用的是 A 接口,內部卻被適配成了 B 接口的實現,系統若是出現太多相似狀況,無異於一場災難。所以,若是不是很必要,能夠不使用適配器,而是直接對系統進行重構。

   適用場景

  • 當想使用一個已存在的類,而它的接口不符合需求時。
  • 你想建立一個可複用的類,該類能夠與其餘不相關的類或不可預見的類協同工做。
  • 你想使用一些已經存在的子類,可是不可能對每個都進行子類化以匹配它們的接口,對象適配器能夠適配它的父接口。

代碼示例

  博客上講的例子三項插頭和雙項插頭的例子很能恰如其分的說明適配器模式,可是我選擇實現《大話設計模式》一書中的本土球員和外籍球員這個案例。背景:教練和一些球員都是英語使用者,他們不懂中文,有一些中國籍球員,他們不懂英文,這個時候教練要正確的把戰術傳達給中國籍球員,中間就須要一個翻譯,翻譯在適配器設計模式中就是最重要的Adapter,它負責把英文轉換爲中文,並傳達給中國籍球員。

1.要被轉換到的目標接口(能夠是個虛基類):Target(UML中的Target),在本例中是Player。(考慮一下是外籍球員要適配本土球員,因此實際上客戶端調用的接口應該是Player提供的方法,客戶代碼至關因而教練,教練把戰術告訴翻譯,翻譯再傳給外籍球員,這就完成了一次適配過程,外籍球員要適配本土球員,入鄉隨俗嘛,那麼這個翻譯就至關因而適配器) Player就是UML中的Target。

#ifndef PLAYER_H_
#define PLAYER_H_
#include <string>

class Player
{
public:
    virtual void attackInEnglish() = 0;
    virtual void defenseInEnglish() = 0;
    Player() = default;
    virtual ~Player() = default;
protected:
    std::string m_strName;
};
#endif
Player
#ifndef LOCALPLAYER_H_
#define LOCALPLAYER_H_
#include <iostream>
#include "Player.h"
class LocalPlayer:public Player
{
public:
    void attackInEnglish() override;
    void defenseInEnglish() override;
    ~LocalPlayer() = default;
    LocalPlayer(const std::string strName)
    {
    m_strName = strName;
    };
};
#endif

#include "LocalPlayer.h"

void LocalPlayer::attackInEnglish()
{
    std::cout << m_strName << " Attack!" << std::endl;
}

void LocalPlayer::defenseInEnglish()
{
    std::cout << m_strName << " Defense!" << std::endl;
}
LocalPlayer

2.外籍球員(須要進行適配的類)

#ifndef FOREIGNPLAYER_H_
#define FOREIGNPLAYER_H_

#include <iostream>
#include <string>
class ForeignPlayer
{
public:
    void attackInChinese();
    void defenseInChinese();
    ForeignPlayer(const std::string strName):m_strName(strName){};
    ForeignPlayer() = default;
    void setName(const std::string strName)
    {
    m_strName = strName;
    } 
    ~ForeignPlayer() = default;
private:
    std::string m_strName;
};
#endif 

#include "ForeignPlayer.h"

void ForeignPlayer::attackInChinese()
{
    std::cout << m_strName << " Jin Gong!" << std::endl;
}

void ForeignPlayer::defenseInChinese()
{
    std::cout << m_strName << " Fang Shou!" << std::endl;
}
adaptee

3.翻譯(適配器,UML圖中的Adapter)

#ifndef ADAPTER_H_
#define ADAPTER_H_
#include "Player.h"
#include "ForeignPlayer.h"
class Adapter : public Player
{
public:
    void attackInEnglish() override;
    void defenseInEnglish() override;
    Adapter(const std::string strName)
    {
    m_strName = strName;
    }
    ~Adapter() = default;
private:
    ForeignPlayer m_objForeignPlayer;
};
#endif

#include "Adapter.h"

void Adapter::attackInEnglish()
{
    m_objForeignPlayer.setName(m_strName);
    m_objForeignPlayer.attackInChinese();
}

void Adapter::defenseInEnglish()
{
    m_objForeignPlayer.setName(m_strName);
    m_objForeignPlayer.defenseInChinese();
}
Adapter

4.教練(客戶端代碼,UML圖中的client)

#include "LocalPlayer.h"
#include "Adapter.h"

int main(int argc,char *argv[])
{
    LocalPlayer objLocalPlayer("William");
    objLocalPlayer.attackInEnglish();
    LocalPlayer objLocalPlayer2("Green");
    objLocalPlayer2.defenseInEnglish();
    Adapter objForeignPlayer("YaoMing");
    objForeignPlayer.attackInEnglish();
    return (1);
}
client
相關文章
相關標籤/搜索