一,定义
适配器模式:结构型模式之一,适配器提供客户类需要的接口,适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用。也就是说:当客户类调用适配器的方法时,在适配器类的内部将调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类。因此,适配器可以使由于接口不兼容而不能交互的类可以一起工作。
适配器模式分为两种:
类适配器(适配器和适配者是继承关系)
对象适配器(适配器和适配者是关联关系)
二,类图
三,成员职责
抽象目标角色:目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。
适配者角色:适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心
在类适配器中,它通过继承Target和Adaptee使二者产生联系
在对象适配器中,它通过继承Target并关联一个Adaptee对象(设置为私有成员)使二者产生联系。
适配器角色:适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法。
四,实现
我们给出以下场景:
现在有两种规格的插座:中式规格插座和英式规格插座,我们现在不改变英国插座的基础,使英国可以转化为中国插座的规格
英国插座(抽象目标类Target)
class uksoket_target
{
public:virtual void ukplug(){cout << "英国插座:英式规格" << endl;}
};
中国插座(适配者类Adaptee)
class chsoket_adaptee //适配者
{
public:void chplug(){cout << "中式规格" << endl;}
};
类适配器
英式插座适配器(适配器类Adapter)
class uksocket_adapter : public uksoket_target,public chsocket_adaptee
{
public:void ukplug() override{cout << "英国插座:";chplug();}
};
测试方法与主函数
void test()
{uksoket_target* uk1 = new uksoket_target();uksoket_target* uk2 = new uksocket_adapter();uk1->ukplug();uk2->ukplug();delete uk1;uk1 = nullptr;delete uk2;uk2 = nullptr;
}int main()
{test();return 0;
}
对象适配器
英国适配器(适配器类Adapter)
class uksocket_adapter : public uksoket_target
{
private:chsocket_adaptee* ch;
public:void ukplug() override{cout << "英国插座:";ch->chplug();}
};
测试方法与主函数
void test()
{uksoket_target* uk1 = new uksoket_target();uksoket_target* uk2 = new uksocket_adapter();uk1->ukplug();uk2->ukplug();delete uk1;uk1 = nullptr;delete uk2;uk2 = nullptr;
}int main()
{test();return 0;
}
五,优缺点
优点:
将目标类和适配器类解耦。通过引入一个适配器类来重用现有的适配者类,而无须修改原有的代码。
增加了类的透明性和复用性,将具体的实现封装在适配器类中,对于客户端类来说是透明的,而且提高了适配器的复用性。
灵活性和扩展性都非常好,符合开闭原则
缺点:
过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
六,适用场景
当想使用一个已存在的类,而它的接口不符合需求时。
你想创建一个可复用的类,该类可以与其他不相关的类或不可预见的类协同工作。