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); }