适配器模式可以用来在现在接口和不兼容的类之间进行适配。

使用这种模式的对象又叫包装器,因为他们是在用一个新接口包装另一个对象。

在设计类的时候往往遇到有些接口不能与现有api一同使用的情况,借助于适配器,你可以不用直接修改这些类也能使用他们。

适配器的特点:

适配器可以被添加到现有代码中以协调俩个不同的接口。从表面上来看,适配器模式很像门面模式,他们都要对别的对象进行包装并改变其呈现的接口,二者之间的差别在于他们如何改变接口。门面元素展现的是一个简化接口,它并不提供额外的选择,而且有时是为了方便完成常见任务它还会做一些假定。而适配器模式则要把一个接口转换为另一个接口,它并不会滤除某些能力,也不会简化接口,如果客户系统期待的api不可用,那么就需要用到适配器模式。

适配器可被实现为不兼容的方法调用之间的一个代码薄层,如果你有一个具有三个字符串参数的函数,但客户系统拥有的却是一个包含三个字符串元素的数组,这时候就可以用一个适配器来衔接二者。

现在看看Prototype库和YUI的get方法转换,这俩个函数的功能比较相似,不过先看看二者之间接口的差别。

//Prototype $ function
function $(){
var elements = 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;
}
elements.push(element);
}
return elements;
} //YUI get method 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;
}

而适配器的实现十分简单:

function PrototypeToYUIAdapter(){
return YAHOO.util.Dom.get(arguments);
}
function YUIToPrototypeAdapter(){
return $.apply(window,el instanceof Array?el:[el]);
}

Prototype 想用YUI的话,只需要 $ = PrototypeToYUIAdapter即可;相反,则YAHOO.util.Dom.get = YUIToPrototypeAdapter 即可。

适配电子邮件API:

下面这是一个替换函数,很多HTML模板的实现也是这个原理:

var DED = {};
DED.util = {
substitute:function(s,o){
return s.replace(/{([^{}]*)}/g,function(a,b){
var r = o[b];
return typeof r==='string' || typeof r==='number'?r:a;
});
}
}

具体实现:

var deMail = (function(){
function request(id,type,callback){
DED.util.asyncRequest(
"GET",
"mail.php",
function(o){
callback(o.responseText);
}
);
}
return {
getMail:function(id,callback){
request(id,'all',callback);
},
sendMail:function(id){
//.....
},
save:function(id){
//...
},
move:function(id,des){
//....
},
archive:function(id){
//...
},
trash:function(id){
//...
},
resportSpam:function(id){
//...
},
formatMessage:function(e){
var e = e || window.event;
try{
e.preventDefault()
}catch(e){
e.returnValue = false;
}
var targrtEl = e.target || e.srcElement;
var id = targrtEl.id.toString().split('-')[1];
deMail.getMail(id,function(msgObject){
var resp = eval('('+msgObject+')');
var details = '<p>{from}';
details+='{date}';
details+='{message}</p>';
$('message-pane').innerHTML = DED.util.substitute(details,resp);
})
}
}
})() addEvent(widow,'load',function(){
var threads = getElementsByClass('thread','a');
for (var i=0,len=threads.length;i<len;++i) {
addEvent(threads[i],'click',formatMessage)
}
})

程序创建完成,但是别的小组那边的人已经使用原来的fooMail系统实现了他们的代码,问题是,他们的方法要求提供的是HTML片段,其构造函数也只接受一个ID,而且他们的getMail只有回调函数这一个参数,而且,他们不想改写全部代码,于是我们决定,要有适配器。

下面我们要从fooMail转到dedMail。

在充分料及了提供方和接收方的情况后,你可以截取来自提供方的逻辑,然后用接收方能够理解的方式对其转换。

先看下fooMail这个api的代码:

fooMail.getMail(function(text){
$('message-pane').innerHTML = text;
});

注意,getMail方法以一个回调方法为参数,这个回调函数被调用时得到的参数是包含着发信人姓名,日期和内容的一段文本。这不算理想,但是fooMail的工程师不想冒着破换系统的危险进行修改,我们就可以为他们写一个简单的适配器,这样他们就不必改变自己的原有代码。

var deMailtoFooMailAdapter = {};
deMailtoFooMailAdapter.getMail = function(id,callback){
deMail.getMail(id,function(resp){
var resp = eval('('+resp+')');
var details = '<p>{from}';
details+='{date}';
details+='{message}</p>';
callback(DED.util.substitute(details,resp));
})
}
fooMail = deMailtoFooMailAdapter;

这段代码中用 deMailtoFooMailAdapter 这个单体对象改写了fooMail对象,该单体对象实现了一个getMail方法,这个方法内部在调用哪个回调函数时会把一段HTML文本作为参数正确的传给它。

适配器适用于客户系统期待的接口与现有API提供的接口不兼容这种场合。它只能用来协调语法上的差异。适配器所适应的俩个方法执行的应该是类似的任务,否则的话它就无法解决问题。如果客户想要一个不同的接口,比如说一个他们用起来更容易一些的接口,那么也可以为此而使用适配器。就像桥接元素和门面元素一样,通过创建适配器,就可以把抽象与实现隔离开来,以便二者独立变化。

适配器的好处有助于避免大规模改写现有客户端代码,其工作机制就是用一个新的接口对现有类的接口进行包装,这个客户程序就能使用这个并非为其量身打造的类而又无需为此大动手术。

读书笔记之 - javascript 设计模式 - 适配器模式的更多相关文章

  1. 读书笔记之 - javascript 设计模式 - 接口、封装和链式调用

    javascript 采用设计模式主要有下面的三方面原因: 可维护性:设计模式有助于降低模块之间的耦合程度.这使代码进行重构和换用不同的模块变得容易,也使程序员在大型项目中合作变得容易. 沟通:设计模 ...

  2. 读书笔记之 - javascript 设计模式 - 门面模式

    门面模式有俩个作用: 简化类的接口 消除类与使用它的客户代码之间的耦合 在javascript中,门面模式常常是开发人员最亲密的朋友.它是几乎所有javascript库的核心原则,门面模式可以使库提供 ...

  3. 读书笔记之 - javascript 设计模式 - 命令模式

    本章研究的是一种封装方法调用的方式.命令模式与普通函数有所不同.它可以用来对方法调用进行参数化处理和传送,经过这样处理过的方法调用可以在任何需要的时候执行. 它也可以用来消除调用操作的对象和实现操作的 ...

  4. 读书笔记之 - javascript 设计模式 - 观察者模式

    在事件驱动的环境中,比如浏览器这种持续寻求用户关注的环境中,观察者模式是一种管理人与其任务(确切的讲,是对象及其行为和状态之间的关系)之间的关系的得力工具.用javascript的话来讲,这种模式的实 ...

  5. 读书笔记之 - javascript 设计模式 - 代理模式

    代理(proxy)是一个对象,它可以用来控制对另一对象的访问.它与另外那个对象实现了同样的接口,并且会把任何方法调用传递给那个对象.另外那个对象通常称为本体.代理可以代替本体被实例化,并使其可被远程访 ...

  6. 读书笔记之 - javascript 设计模式 - 享元模式

    本章探讨另一种优化模式-享元模式,它最适合于解决因创建大量类似对象而累及性能的问题.这种模式在javascript中尤其有用,因为复杂的javascript代码很快就会用光浏览器的所有可用内存,通过把 ...

  7. 读书笔记之 - javascript 设计模式 - 单体模式

    单体是一个用来划分命名空间,并将一批相关方法和属性组织在一起的对象,如果它可以被实例化,那么它只能被实例化一次. 单体模式,就是将代码组织为一个逻辑单元,这个逻辑单元中的代码可以通过单一的变量进行访问 ...

  8. 读书笔记之 - javascript 设计模式 - 组合模式

    组合模式是一种专为创建Web上的动态用户界面而量身定制的模式,使用这种模式,可以用一条命令在对各对象上激发复杂的或递归的行为. 在组合对象的层次体系中有俩种类型对象:叶对象和组合对象.这是一个递归定义 ...

  9. 读书笔记之 - javascript 设计模式 - 工厂模式

    一个类或者对象中,往往会包含别的对象.在创建这种对象的时候,你可能习惯于使用常规方式,即用 new 关键字和类构造函数. 这会导致相关的俩个类之间产生依赖. 工厂模式,就是消除这俩个类之间的依赖性的一 ...

随机推荐

  1. Bzoj 1726: [Usaco2006 Nov]Roadblocks第二短路 dijkstra,堆,A*,次短路

    1726: [Usaco2006 Nov]Roadblocks第二短路 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 969  Solved: 468[S ...

  2. Hadoop之Pig安装

    Pig可以看做是Hadoop的客户端软件,使用Pig Latin语言可以实现排序.过滤.求和.分组等操作. Pig的安装步骤: 一.去Pig的官方网站下载.http://pig.apache.org/ ...

  3. Android NDK开发Crash错误定位[转]

    使用 ndk-stack 的时候需要你的 lib 编译为 debug版的,通常需要下面的修改: 1. 修改 android.mk,增加,为 LOCAL_CFLAGS 增加 -g 选项 2. 修改 ap ...

  4. 找回linux丢失的磁盘空间

    最近一台服务器空间总是报警,磁盘空间不足. 使用 df 命令查看,磁盘空间耗用接近 100%,将机器上过期的数据以及日志清理掉,但是空间很快又是接近 100%. 使用 du 查看,想找出磁盘空间被耗用 ...

  5. 安装Office时出现windows installer服务不能更新一个或多个受保护的windows文件错误的解决方法

    今天在Windows XP上安装Microsoft Office 2010时,总是遇到“Windows Installer服务不能更新一个或多个受保护的windows文件,安装失败,正在回滚更改”提示 ...

  6. 375. Guess Number Higher or Lower II

    最后更新 四刷? 极大极小算法..还是叫极小极大的.. 首先要看怎么能保证赢. 比如2个数,猜第一个猜第二个都能保证下一轮我们赢定了,为了少交钱,我们猜小的. 比如3个数,猜第二个才能保证下一轮再猜一 ...

  7. ABAP提示信息对话框

     1.   call function 'POPUP_TO_CONFIRM_WITH_MESSAGE'         exporting           diagnosetext1 = '数据为 ...

  8. NuGet的使用和服务搭建

    问题的由来 最近部门,在开发的时候遇到一个问题,现在有项目A B C三个项目,项目B和C分别提供了组件库由项目A直接引用.那么每次开打项目A获取最新后,同时还得打开项目B C获取最新然后编译一次.抛开 ...

  9. Android 完美退出 App (Exit)

    最近两天为了解决Android上面退出程序问题折腾了半死,在google & baidu 上面找了很久.很久出来的完全千篇一律,说的方法有三,但是经过我试验后全部不行. 三个方法分别是: ki ...

  10. [转]开源应用架构之asterisk

    作者:Russell Bryant 翻译:jiazhengfeng Asterisk[1]是一款GPLv2协议下的开源电话应用平台.简单来说,Asterisk是一个服务器应用,能够完成发起电话呼叫.接 ...