适配器模式概述
适配器模式可用来在现有接口和不兼容的类之间进行适配。使用这种模式的对象又叫包装器(wrapper)。
适配器特点
从表面看,适配器模式很像门面模式。她们都要对别的对象进行包装并改变其呈现的接口。
二者的区别在于她们如何改变接口:
- 门面元素展现的是一个简化的接口,她并不提供额外的选择,而且有时为了方便完成任务她还会做出一些假定。
- 适配器则要把一个接口转换为另一个接口,她并不滤除某些能力,也不会简化接口。
假设有一个对象,还有一个以三个字符串为参数的函数:
var clientObject = { string1: ‘foo‘, string1: ‘bar‘, string1: ‘baz‘ }; function interfaceMethod(str1, str2, str3){ console.log(‘ehhe‘); }
为了把clientObject作为参数传递给interfaceMethod,需要用到适配器。如下:
function clientToInterfaceAdapter(o){//适配器 interfaceMethod(o.string1, o.string2, o.string3); }
示例:适配两个库
下面我们来实现从Prototype库的$函数到YUI的get方法的转换。这两个函数的功能比较相似,不过先看看她们在接口方面的差别:
function $(){ var elments = new Array(); for(var i=0; i<arguments.length; i++){ var element = arguments[i]; if(typeof element == ‘string‘){ element = document.getElementById(element); } if(arguments.length == 1){ return element; } elments.push(element); } return elements; } YAHOO.util.Dom.get = function(el){ if(YAHOO.lang.isString(el)){ return document.getElementById(el); } if(YAHOO.lang.isArray(el)){ var c = []; for(var i= 0, len=el.length; i<len; i++){ c[c.length] = YAHOO.util.Dom.get(el[i]); } return c; } if(el){ return el; } return null; }
二者的区别主要在于:get具有一个参数,这个参数可以是一个HTML元素、字符串或者由字符串或HTML元素组成的数组,与此不同,$函数没有正式列出参数,而是允许客户传入任意数目的参数,不管是字符串还是HTML元素都行。
如果要实现从$方法到get方法的转换(或者相反),那么用于这个用途的适配器会是什么样子呢?
function $2getAdapter(){ return YAHOO.util.Dom.get(arguments); } function get2$Adapter(el){ return $.apply(window, el instanceof Array ?el: [el]); }
对于从Prototype改投YUI的人应该如下使用:
$ = $2getAdapter;
相反的如下使用:
YAHOO.util.Dom.get = get2$Adapter;
适配器模式的使用场合
适配器适用于客户系统期待的接口与现有API提供的接口不兼容这种场合。她只能用来协调语法上的差异问题。适配器所适配的两个方法执行的应该是类似的任务,否则她就解决不了问题。
适配器模式之利
适配器模式有利于避免大规模改写现有客户代码。
适配器模式之弊
如果现有API还未定形,或者新街口还未定形,那么适配器可能不会一直管用。