適配器模式
將一個類的接口轉換成客戶希望的另外一個接口。適配器模式使得原本由於接口不兼容而不能一起工作的那些類可以一起工作。
- Target(目標接口) :客戶所期待的接口,可以是具體的或抽象的類,也可以是接口
- Adaptee(需要適配的類):需要適配的類或適配者類。
- Adapter(適配器):包裝一個需要適配的接口,把原接口轉換成目標接口。
通俗的理解:
“適配器模式使得原本由於接口不兼容而不能一起工作的那些類可以一起工作。好比日本現在就只提供110V的電壓,而我的電腦就需要220V的電壓,那怎麼辦啦?適配器就是幹這活的,在不兼容的東西之間搭建一座橋樑,讓二者能很好的兼容在一起工作。”
使用適配器的場景及優點
優點
- 降低了一個功能點的難度,可以對現有的類進行包裝,就可以進行使用了。
- 提高了項目的質量,降低了成本。
場景
- 使用已經存在的類,但是他的接口與你的需求不同。
- 調用者和提供則都不太容易修改的時候使用適配器模式。
UML類圖
類適配器
Adapter繼承Target類與Adaptee類,Adapter重寫Target的Request方法,做一些處理,實際調用的是Adaptee的SpecificRequest方法。
對象適配器
適配器繼承於Target類,同時Adapter類中有一個Adaptee類型的成員變量,Adapter重寫Request函數,使用Adaptee類型的成員變量調用Adaptee的SpecificRequest函數完成適配。
比較
類適配器
- 由於Adapter直接繼承自Adaptee類,所以,在Adapter類中可以對Adaptee類的方法進行重定義;
- 如果在Adaptee中添加了一個抽象方法,那麼Adapter也要進行相應的改動,這樣就帶來高耦合;
- 如果Adaptee還有其它子類,而在Adapter中想調用Adaptee其它子類的方法時,使用類適配器是無法做到的。
對象適配器
- 有的時候,你會發現,不是很容易去構造一個Adaptee類型的對象;
- 當Adaptee中添加新的抽象方法時,Adapter類不需要做任何調整,也能正確的進行動作;
- 可以使用多態的方式在Adapter類中調用Adaptee類子類的方法
由於對象適配器的耦合度比較低,所以在很多的書中都建議使用對象適配器。在我們實際項目中,也是如此,能使用對象組合的方式,就不使用多繼承的方式。
Code
類適配器
#include <iostream>
class Target{
public:
virtual ~Target(){}
virtual void Request(){
std::cout<<"Target::Request"<<std::endl;
}
};
class Adaptee{
public:
virtual ~Adaptee(){}
virtual void SpecificRequest(){
std::cout<<"Adaptee::SpecificRequest"<<std::endl;
}
};
class Adapter:public Target ,Adaptee{
public:
void Request(){
Adaptee::SpecificRequest();
}
};
int main()
{
Target* TargetObj = new Adapter();
TargetObj->Request();
delete TargetObj;
return 0;
}
對象適配器
#include <iostream>
class Target{
public:
Target(){}
virtual ~Target(){}
virtual void Request(){
std::cout<<"Target::Request"<<std::endl;
}
};
class Adaptee{
public:
void SpecificRequest(){
std::cout<<"Adaptee::SpecificRequest"<<std::endl;
}
};
class Adapter:public Target{
public:
Adapter():m_Adaptee(new Adaptee){}
~Adapter(){
if(m_Adaptee){
delete m_Adaptee;
}
}
void Request(){
m_Adaptee->SpecificRequest();
}
private:
Adaptee* m_Adaptee;
};
int main()
{
Target* TargetObj = new Adapter();
TargetObj->Request();
delete TargetObj;
return 0;
}