设计模式C++适配器
注:参考视频:【设计模式(完整版)】2.1适配器_哔哩哔哩_bilibili
分类:(类)结构型,(对象)结构型
问题:开发一款股票市场检测程序,会从不同来源下载XML格式的股票数据,然后向用户呈现出分析图表.但是,分析函数库只兼容JSON格式的数据.
这个问题转换成生活中就是比较常见的USB转TypeC转接头,我们要做的就是创建一个转接头.
下面第一个类图稍微了解一下即可,因为这个类图中adapter需要继承两个基类(多继承),在C++中可以,但是在其他语言就不行了.
1.类适配器不需要封装任何对象,因为它同时继承了客户端和服务的行为.
Adapte与Service不是继承的关系了,而是对象的关系,Adapter中有一个Adaptee的对象(也就是指针)这些类图是根据JAVA语言编写的.
1.客户端(Client)是包含当前程序业务逻辑的类.
2.客户端接口(Client Interface)描述了其他类与客户端代码必须遵守的协议.
3.服务(Service)中有一些功能类.客户端和其接口不兼容.
4.适配器(Adapter)是一个可以同时与客户端和服务交互的类:它在实现客户端接口的同时封装了服务对象.
5.客户端代码只需通过接口与适配器交互即可,无需与具体的适配器类耦合.
解决方案:讲一个类的接口转换为客户希望的另一个接口.使得原本不兼容的一些类可以一起工作.即创建一个适配器.这是一个特殊的对象,能够转换对象接口.
完整代码:
#include <iostream>
//Target:客户端需要的目标接口
class JasonInfo
{
public:
virtual ~JasonInfo() {}
virtual std::string request() const
{
return "Some Jason information....";
}
};
//Adaptee:客户端不兼容的接口,需要转换为Target接口
class XmlInfo
{
public:
std::string spectialRequest() const
{
return "Some Xml information......";
}
};
//Adapter:适配器,就是把Adaptee包装起来,让他看上去像是Target
class XmlJasonAdapter :public JasonInfo
{
private:
XmlInfo* m_adaptee;
public:
XmlJasonAdapter(XmlInfo* m_adaptee):m_adaptee(m_adaptee){}
virtual std::string request() const override
{
std::string string = m_adaptee->spectialRequest();
return "Jason<-XmlJasonAdaptor<-"+string;
}
};
void clientCode(const JasonInfo* info)
{
std::cout << "股票分析软件运行Jason:"
<< std::endl;
std::cout << info->request() << std::endl;
std::cout << "------------------------"
<< std::endl;
}
int main()
{
JasonInfo jasonInfo;
clientCode(&jasonInfo);
//不兼容,所以我们要解决下面注释的这个问题
XmlInfo xmlInfo;
//clientCode(&xmlInfo);
XmlJasonAdapter jasonAdapter(&xmlInfo);
clientCode(&jasonAdapter);
}
下面适配器模式演示基于经典的"方钉和圆孔"问题:
RoundHole类就是client,client中有一个接口,针对的是RoundPeg(圆钉),但是我们现在能提供的只有Squareapeg(方钉),所以需要一个适配器SquarePegAdapter,把这个方钉裹起来看起来就像一个圆钉一样.这样就可以被client调用了.那求半径时就重写方法,return peg.getWidth()*sqrt(2)/2.
优点:
单一职责原则,可以将接口或数据转换代码从程序主要业务逻辑中分离.
开闭原则:只要客户端代码通过客户端接口与适配器进行交互,你就能在不修改现有客户端代码的情况下在程序中添加新类型的适配器.
缺点:
代码整体复杂度增加,因为需要新增一系列接口和类.有时直接更改服务类使其与其他代码兼容会更简单.