场景:我们已经有一些已有的系统对外提供服务,但是这些服务不能符合客户的接口形式要求,或者不是基于开放的标准协议构建的。这时候我们需要在已有接口之上增加一个适配层来满足对外的服务需要。
适配层往往不是提前的设计,而是基于现有现有的系统进行的妥协和适配。生活中常见的例子比如:美国的电压是110V,中国的电压是220V,购买自美国的电脑电源就需要一个电源适配器。在IE浏览器盛行的时代,他的很多接口都不是符合后来的WEB标准的,所以很多前端框架为了能够提供基于标准协议的SDK,会为了IE做许多的适配工作。
通过上面的例子我们看到在适配器模式中会有几个角色:
- 已有接口能力的提供者,但通常接口是不符合使用者需要或者规范的,我们称之为
Adaptee
(适应者) - 适配对象:对
Adaptee
的接口能力进行兼容或适配,使得其能够符合使用者的规范或需要 - 标准对象:通常来讲处于客户(使用方)的要求,需要提供一个标注的契约,让
Adaptee
去做适配
这是《设计模式》中的一个插图,左侧系统是指接口的使用方,他会有自己期望的接口形式(或标准),而实际的提供接口系统却并并不能满足,于是需要一个适配层做实现期望接口的实现,但内部会基于Vendor Class
的已有能力来实现,并做兼容适配。
代码实例
下面我们以上面提到的对IE浏览器的接口能力的适配为例来写一份示例代码,这其实在以前的老版jQuery实现中非常常见。
public class IEDriver {
Element clickElement(String selector) {
System.out.println("IE select element by " + selector);
return null;
}
}
public interface WebDriver {
Element selectElement(String selector);
}
我们先看上面的代码,IEDriver提供了元素选择的能力clickElement;但是却并不符合浏览器规范中的元素选择的接口selectElement,以Chrome为例,标准的实现可能是这样的,直接调用即可。
class ChromeDriver implements WebDriver {
@Override
public Element selectElement(String selector) {
System.out.println("Chrome select element by " + selector);
return null;
}
}
但在IE的环境中,这个接口并不存在,所以我们使用适配器模式,对IEDriver加上一层适配器
class WebDriverAdapter implements WebDriver {
private IEDriver ieDriver;
public WebDriverAdapter(IEDriver ieDriver) {
this.ieDriver = ieDriver;
}
@Override
public Element selectElement(String selector) {
System.out.println("WebDriverAdapter select element by " + selector);
return ieDriver.clickElement(selector);
}
}
这样一来,在IE环境下,我们直接调用适配器的标准接口selectElement就可以了。而适配器会持有IEDriver的引用,实际实现会使用器clickElement。最后是一段使用代码
public class AdapterDemo {
public static void main(String[] args) {
IEDriver ieDriver = new IEDriver();
WebDriver webDriverAdapter = new WebDriverAdapter(ieDriver);
webDriverAdapter.selectElement("#ieSelector");
WebDriver chromeDriver = new ChromeDriver();
chromeDriver.selectElement("#webSelector");
}
}
输出结果:
WebDriverAdapter select element by #ieSelector
IE select element by #ieSelector
Chrome select element by #webSelector
结语
我们的设计大部门情况下都无法抛开老系统,因此适配器模式能够让我们既能够勇敢的面向未来进行扩展设计,也能够让现有的系统能够正常的工作。
但要注意的是,适配器模式屏蔽了已有系统的逻辑,过渡使用反而会使得系统难以理解和预测,因此也要留一个计划,在适当的实际把适配器换成标准实现。