1. 原理
demo:
在开发过程中,你决定在程序中整合一个第三方智能分析函数库。但是遇到了一个问题,那就是分析函数库只兼容 JSON 格式的数据。
你可以修改程序库来支持 XML。但是,这可能需要修改部分依赖该程序库的现有代码。甚至还有更糟糕的情况,你可能根本没有程序库的源代码,从而无法对其进行修改。
你可以创建一个适配器。这是一个特殊的对象,能够转换对象接口,使其能与其他对象进行交互。
适配器模式通过封装对象将复杂的转换过程隐藏于幕后。被封装的对象甚至察觉不到适配器的存在。例如,你可以使用一个将所有数据转换为英制单位 (如英尺和英里) 的适配器封装运行于米和千米单位制中的对象。
适配器不仅可转换不同格式的数据,其还助于采用不同接口的对象之间的合作。运作方式如下:
1 - 适配器实现与其中一个现有对象兼容的接口。
2 - 现有对象可以使用该接口安全地调用适配器方法。
3 - 适配器方法被调用后将以另一个对象兼容的格式和顺序将请求传递给该对象。
适配器有两种,分别是对象适配器、类适配器,一般采用对象适配器。
2. 适配器的分类
2.1 对象适配器
2.2 类适配器
类适配器使用了继承机制:适配器同时继承两个对象的接口。请注意,这种方式仅能在支持多重继承的编程语言中实现,例如 C++。
3. 模式介绍
3.1 软件动机
在软件系统中,由于应用环境的变化,常常需要将 “一些现存的对象” 放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的。
如何应对这种 “迁移的变化” ?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?
3.2 模式定义
将一个类的接口转换成客户希望的另一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
3.3 要点总结
a). Adapter模式主要应用于 “希望复用一些现存的类,但是接口又与复用环境要求不一致的情况”,在遗留代码复用、类库迁移等方面非常有用。
b). GoF 23 定义了两种Adapter模式的实现结构:对象适配器和类适配器。但类适配器采用 “多继承” 的实现方式,一般不推荐使用。对象适配器采用 “对象组合” 的方式,更符合松耦合特点。
c). Adapter模式可以实现的非常灵活,不必拘泥于 GoF23 中定义的两种结构。例如,完全可以将Adapter模式中的 “现存对象” 作为新的接口方法参数,来达到适配的目的。
4. 代码实现
//目标接口(新接口)
class ITarget{
public:
virtual void process() = 0;
};
//遗留接口(老接口)
class IAdaptee{
public:
virtual void foo(int data) = 0;
virtual int bar() = 0;
};
//遗留类型
class OldClass : public IAdaptee{
//...
};
class Adapter : public ITarget{ //继承
protected:
IAdaptee* pAdaptee; //组合对象
public:
Adapter(IAdaptee* pAdaptee){
this->pAdaptee = pAdaptee;
}
virtual void process(){
int data = pAdaptee->bar();
pAdaptee->foo(data);
}
};
int main(){
IAdaptee* pAdaptee = new OldClass();
ITarget* pTarget = new Adapter(pAdaptee );
pTarget->process();
}
类适配器:
// 类适配器——使用继承的适配器
#include <iostream>
#include <string>
// Banner类——现在实际的情况
class Banner
{
public:
std::string banner_str;
Banner(std::string banner_str) : banner_str(banner_str) {}
// 现实中实际有的方法
void show_with_paren()
{
// std::cout << "Banner paren" << std::endl;
std::cout << "(" << banner_str << ")" << std::endl;
}
void show_with_aster()
{
// std::cout << "Banner aster" << std::endl;
std::cout << "*" << banner_str << "*" << std::endl;
}
};
// 需求接口——最终的目标接口
// 这里使用纯虚函数来建立抽象类,实现一个接口
class Print
{
public:
virtual void print_weak() = 0;
virtual void print_strong() = 0;
virtual ~Print() = default;
};
// 中间的适配器类
class PrintBanner : private Banner, public Print
{
public:
PrintBanner(std::string banner_str):Banner(banner_str)
{
}
void print_weak() override
{
std::cout << "print_weak:";
show_with_paren();
}
void print_strong() override
{
std::cout << "print_strong";
show_with_aster();
}
~PrintBanner() = default;
};
int main()
{
Banner banner("banner");
banner.show_with_paren();
banner.show_with_aster();
// 适配器大法
Print *print = new PrintBanner("print");
print->print_strong();
print->print_weak();
}