Adapter适配器模式
作用:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适用场景
已存在的类,它的方法和需求不匹配时(方法结果相同或相似)
也就是方法的结果相同或相似,在这个基础上出现这种场景时,适配器为了复用一些现有的类,系统的数据和行为都正确,但是接口不符合,这个时候就可以采取适配器模式
不是软件设计阶段考虑的设计模式,是随着软件维护,由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决方案
也就是说,如果我们在做一个新的系统,在设计的时候不要考虑适配器,适配器有点亡羊补牢的感觉,设计阶段呀尽量避免使用,但是随着项目的不断发展就要考虑适配器模式了。
优点
能提高类的透明性和复用,现有的类复用但不需要改变
解决了现有类和目标类不匹配的问题
目标类和适配器类解耦,提高程序扩展性
我们可以使用适配器模式开发自己的功能
符合开闭原则
具体的实现都在适配器中,客户端知道的只有适配器类,扩展的话,我们只需要扩展适配器就可以,而原有的类是不需要变化的
缺点
适配器编写过程中需要全面考虑,可能会增加系统的复杂性
增加系统代码可读的难度
如果过多的使用适配器,会让我们的系统非常凌乱,不易整理和进行把握。比如,我们调用第一个接口,其实内部已经被适配成了调用第二个接口的实现,这种情况在读代码的时候就很容易蒙圈,所以说增加了系统代码的可读的难度。
扩展
对象适配器
符合组合复用原则,并且使用委托机制
类适配器
通过类继承来实现
分为类适配器模式和对象适配器模式。
系统的数据和行为都正确,但接口不符时,我们应该考虑使用适配器,目的是使控制范围之外的一个原有对象与某个接口匹配。适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况。
想使用一个已经存在的类,但如果它的接口,也就是它的方法和你的要求不相同时,就应该考虑用适配器模式。
比如购买的第三方开发组件,该组件接口与我们自己系统的接口不相同,或者由于某种原因无法直接调用该组件,可以考虑适配器。
UML图如下:
图1:类模式适配器
图2:对象模式适配器
代码如下:
Adapter.h
#ifndef _ADAPTER_H_
#define _ADAPTER_H_
//目标接口类,客户需要的接口
class Target
{
public:
Target();
virtual ~Target();
virtual void Request();//定义标准接口
};
//需要适配的类
class Adaptee
{
public:
Adaptee();
~Adaptee();
void SpecificRequest();
};
//类模式,适配器类,通过public继承获得接口继承的效果,通过private继承获得实现继承的效果
class Adapter:public Target,private Adaptee
{
public:
Adapter();
~Adapter();
virtual void Request();//实现Target定义的Request接口
};
//对象模式,适配器类,继承Target类,采用组合的方式实现Adaptee的复用
class Adapter1:public Target
{
public:
Adapter1(Adaptee* adaptee);
Adapter1();
~Adapter1();
virtual void Request();//实现Target定义的Request接口
private:
Adaptee* _adaptee;
};
#endif
Adapter.cpp
#include "Adapter.h"
#include <iostream>
using namespace std;
Target::Target()
{}
Target::~Target()
{}
void Target::Request()
{
cout << "Target::Request()" << endl;
}
Adaptee::Adaptee()
{
}
Adaptee::~Adaptee()
{
}
void Adaptee::SpecificRequest()
{
cout << "Adaptee::SpecificRequest()" << endl;
}
//类模式的Adapter
Adapter::Adapter()
{
}
Adapter::~Adapter()
{
}
void Adapter::Request()
{
cout << "Adapter::Request()" << endl;
this->SpecificRequest();
cout << "----------------------------" <<endl;
}
//对象模式的Adapter
Adapter1::Adapter1():_adaptee(new Adaptee)
{
}
Adapter1::Adapter1(Adaptee* _adaptee)
{
this->_adaptee = _adaptee;
}
Adapter1::~Adapter1()
{
}
void Adapter1::Request()
{
cout << "Adapter1::Request()" << endl;
this->_adaptee->SpecificRequest();
cout << "----------------------------" <<endl;
}
main.cpp
#include "Adapter.h"
int main()
{
//类模式Adapter
Target* pTarget = new Adapter();
pTarget->Request();
//对象模式Adapter1
Adaptee* ade = new Adaptee();
Target* pTarget1= new Adapter1(ade);
pTarget1->Request();
//对象模式Adapter2
Target* pTarget2 = new Adapter1();
pTarget2->Request();
return 0;
}
在Adapter模式的两种模式中,有一个很重要的概念就是接口继承和实现继承的区别和联系。接口继承和实现继承是面向对象领域的两个重要的概念,接口继承指的是通过继承,子类获得了父类的接口,而实现继承指的是通过继承子类获得了父类的实现(并不统共接口)。在C++中的public继承既是接口继承又是实现继承,因为子类在继承了父类后既可以对外提供父类中的接口操作,又可以获得父类的接口实现。当然我们可以通过一定的方式和技术模拟单独的接口继承和实现继承,例如我们可以通过private继承获得实现继承的效果(private继承后,父类中的接口都变为private,当然只能是实现继承了。),通过纯抽象基类模拟接口继承的效果,但是在C++中pure virtual function也可以提供默认实现,因此这是不纯正的接口继承,但是在Java中我们可以interface来获得真正的接口继承了。