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

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

在设计类的时候往往遇到有些接口不能与现有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. JavaScript高级程序设计61.pdf

    JSON对象 早期的JSON解析器就是使用JavaScript的eval()函数,ECMAScript5对解析JSON的行为做出了规定,定义了全局对象JSON. JSON对象有2个方法:stringi ...

  2. .net常見面試題(三)

    1, 请你说说.NET中类和结构的区别? 答:结构和类具有大体的语法,但是结构受到的限制比类要多.结构不能申明有默认的构造函数,为结构的副本是又编译器创建和销毁的,所以不需要默认的构造函数和析构函数. ...

  3. Bzoj 2662: [BeiJing wc2012]冻结 dijkstra,堆,分层图,最短路

    2662: [BeiJing wc2012]冻结 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 647  Solved: 348[Submit][Sta ...

  4. kafka consumer 分区reblance算法

    转载请注明原创地址 http://www.cnblogs.com/dongxiao-yang/p/6238029.html 最近需要详细研究下kafka reblance过程中分区计算的算法细节,网上 ...

  5. PostgreSQL相关的软件,库,工具和资源集合

    PostgreSQL相关的软件,库,工具和资源集合. 备份 wal-e - Simple Continuous Archiving for Postgres to S3, Azure, or Swif ...

  6. CONTROLS: <> TYPE TABLEVIEW USING SCREEN<>.在 ABAP/4 中声明表格 控制

    在 ABAP/4 中声明表格 控制 在屏幕中使 用表格控制 时,必须在 ABAP/4 程序中同时 声明表格控 制结构和表 格控制字段 . 例如: TABLES:   SFLIGHT. CONTROLS ...

  7. 【转】Android 快捷方式的创建

    http://blog.csdn.net/lenmoyouzi/article/details/16939977 一.在日常开发中,我们经常会遇到这样的需求就是网桌面添加快捷方式:常见的快捷方式有两种 ...

  8. java的一些程序

    1.文件读取并打印 import java.io.*;public class readandprint{//*********Found********public static void main ...

  9. mysql导出部分数据的几种方法(摘录)

    mysql虽然可以使用mysqldump来进行数据的到处,可是在很多场合的需求都不一样,比如我只要导出某个字段呢?只要导出某些我需要的数据呢? 这个时候mysqldump可能就不大好使了 方法一. i ...

  10. Objective-C:内存管理

    1 传统内存管理 Objective-C对象的生命周期可以分为:创建.存在.消亡. 1.1 引用计数 类似Java,Objective-C采用引用计算(reference counting)技术来管理 ...