适配器模式(c++实现)
适配器模式
- 在软件开发中采用类似于电源适配器的设计和编码技巧被称为适配器模式。
- 通常情况下,客户端可以通过目标类的接口访问它所提供的服务。有时,现有的类可以满足客户类的功能需要,但是它所提供的接口不一定是客户类所期望的,这可能是因为现有类中方法名与目标类中定义的方法名不一致等原因所导致的。
- 在这种情况下,现有的接口需要转化为客户类期望的接口,这样保证了对现有类的重用。如果不进行这样的转化,客户类就不能利用现有类所提供的功能,适配器模式可以完成这样的转化。
- 在适配器模式中可以定义一个包装类,包装不兼容接口的对象,这个包装类指的就是适配器(Adapter),它所包装的对象就是适配者(Adaptee),即被适配的类。
- 适配器提供客户类需要的接口,适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用。也就是说:当客户类调用适配器的方法时,在适配器类的内部将调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类。因此,适配器可以使由于接口不兼容而不能交互的类可以一起工作。这就是适配器模式的模式动机。
UML类结构图如下:
- Target
- Target1
- Adapter
- Adaptee
Target1是Target的子类,Target是客户需要的目标类。Adapter通过适配需要适配的类Adaptee。然后通过统一的接口Request提供对外服务。下面放代码实现:
- adapter.h
#ifndef ADAPTER_H
#define ADAPTER_H
#include "adaptee.h"
class Target
{
public:
Target();
virtual ~Target();
virtual void Request();
};
class Target1 : public Target
{
public:
Target1();
virtual ~Target1() override;
virtual void Request() override;
};
class Adapter : public Target
{
public:
Adapter(Adaptee* adaptee);
~Adapter();
void Request();
Adaptee* m_Adaptee;
};
#endif // ADAPTER_H
- adapter.cpp
#include <QDebug>
#include "adapter.h"
#define DELETEOBJECT(x) if(x != nullptr) { delete x; x = nullptr;}
Adapter::Adapter(Adaptee* adaptee)
{
m_Adaptee = adaptee;
}
Adapter::~Adapter()
{
DELETEOBJECT(m_Adaptee);
}
void Adapter::Request()
{
m_Adaptee->SpecialRequest();
}
void Target::Request()
{
}
void Target1::Request()
{
qDebug() << "普通请求";
}
- adaptee.h
#ifndef ADAPTEE_H
#define ADAPTEE_H
class Adaptee
{
public:
Adaptee();
void SpecialRequest();
};
#endif // ADAPTEE_H
- adaptee.cpp
#include <QDebug>
#include "adaptee.h"
Adaptee::Adaptee()
{
}
void Adaptee::SpecialRequest()
{
qDebug() << __FUNCTION__;
}
- main.cpp
#include "adapter.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Target* target = new Target1();
target->Request();
Adaptee* adaptee = new Adaptee();
Target* target1 = new Adapter(adaptee);
target1->Request();
return a.exec();
}
使用适配器之后对外的统一接口都变成
Target.Request()
适配器模式遵照了以下几个设计原则:
- 依赖倒转原则
- 迪米特法则
参考《大话设计模式》和 https://design-patterns.readthedocs.io/zh_CN/latest/index.html