2018-09-19 22:12:25ios
適配器模式(Adapter):將一個類的接口轉換成客戶但願的另一個接口。Adapter模式使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠一塊兒工做。(注:C++ std的bind函數不就是作個的嗎)。適配器模式,就像是一個轉接頭,我只有三項插座,可是這個電器只有兩個插頭,那麼至於要在中間加一個轉接器,讓三項插座看起來是雙項插座,這樣就能使用了。它的做用就是「有個東西,已經在這裏了,你要使用它,可是又不能使用,短期內又不能改變它,那麼這個時候你就要想辦法去適配它」。所謂適配器就是使一個東西適合另外一個東西的東西。設計模式
在軟件開發中,系統的數據和行爲都正確,但接口不符合時,應該考慮適配器,目的是使控制範圍以外的一個原有對象與某個接口匹配。適配器模式主要適用於但願複用一些現存的類,可是接口又和複用環境不一致的環境。適配器模式分兩種:類適配器模式和對象適配器模式。類適配器模式經過多重繼承對一個接口與另外一個接口進行匹配。因此適配器模式的使用場景就是兩個類所作的事情相同或者類似,可是具備不一樣的接口是可使用它。這樣一來,客戶端代碼就能夠同一調用一個接口了。在雙方都不太容易修改接口的時候再使用適配器模式。ide
類適配器(UML):適配器核心Adapter直接繼承自Adaptee函數
對象適配器(UML):(核心Adapter和Adaptee是關聯關係)spa
Target:這是客戶端所期待的接口,目標能夠是具體的或者抽象的類,也能夠是接口(注:C++沒有接口的概念,但虛基類能夠替代接口的做用).net
Adapter:經過內部包裝一個Adaptee對象,把源接口轉換成目標接口。是適配器模式的核心,具備將Adaptee包裝成Target的職責。翻譯
Aadptee:須要適配的類設計
本部分來自於博客:https://blog.csdn.net/liang19890820/article/details/669732963d
類適配器包含如下特色:code
對象適配器包含如下特色:
因爲對象適配器的耦合度比較低,因此在不少的書中都建議使用對象適配器。
優勢:
缺點:
例如,看到調用的是 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
#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; }
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; }
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(); }
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); }