一、定义

  适配器模式可用来在现有接口和不兼容的类之间进行匹配。使用这种模式的对象又叫包装器(wrapper),因为它们是在用一个新的接口包装另一个对象。在设计类的时候旺旺会遇到有些接口不能与现有API一同使用的情况。借助于适配器,你不用直接修改这些类也能使用它们。 

  适配器可以被添加到现有代码中以协调两个不同的接口。如果现有代码的接口能很好的满足需要,那就可能没有必要使用适配器。但要是现有接口对于手头的工作来说不够直观或实用,那么可以使用适配器来提供一个更简化或更丰富的接口。

var clientObject = {
string1: 'foo',
string2: 'bar',
string3: 'baz'
}; function interfaceMethod(str1, str2, str3) {
// ...
} // 为了把clientObject作为参数传递给interfaceMethod,需要用到适配器。
function clientToInterfaceAdapter(o) {
interfaceMethod(o.string1, o.string2, o.string3)
}
// 现在就可以把整个对象传递给这个函数
clientToInterfaceAdapter(clientObject);

  clientToInterfaceAdapter函数的作用就在于对interfaceMethod函数进行包装,并把传递给它的参数转换为后者需要的形式。

  在这里,嵌入进大叔的鸭子与火鸡的例子。

鸭子(Dock)有飞(fly)和嘎嘎叫(quack)的行为,而火鸡虽然也有飞(fly)的行为,但是其叫声是咯咯的(gobble)。如果你非要火鸡也要实现嘎嘎叫(quack)这个动作,那我们可以复用鸭子的quack方法,但是具体的叫还应该是咯咯的,此时,我们就可以创建一个火鸡的适配器,以便让火鸡也支持quack方法,其内部还是要调用gobble。

//鸭子
var Duck = function(){ };
Duck.prototype.fly = function(){
throw new Error("该方法必须被重写!");
};
Duck.prototype.quack = function(){
throw new Error("该方法必须被重写!");
}
//火鸡
var Turkey = function(){ };
Turkey.prototype.fly = function(){
throw new Error(" 该方法必须被重写 !");
};
// 火鸡——咯咯地叫
Turkey.prototype.gobble = function(){
throw new Error(" 该方法必须被重写 !");
};
//具体的鸭子
var MallardDuck = function () {
Duck.apply(this);
};
MallardDuck.prototype = new Duck(); //原型是Duck
MallardDuck.prototype.fly = function () {
console.log("可以飞翔很长的距离!");
};
// 鸭子——嘎嘎叫
MallardDuck.prototype.quack = function () {
console.log("嘎嘎!嘎嘎!");
};
// 具体的火鸡
var WildTurkey = function () {
Turkey.apply(this);
};
WildTurkey.prototype = new Turkey(); //原型是Turkey
WildTurkey.prototype.fly = function () {
console.log("飞翔的距离貌似有点短!");
};
WildTurkey.prototype.gobble = function () {
console.log("咯咯!咯咯!");
};
// 让火鸡也支持quack方法的适配器
var TurkeyAdapter = function(oTurkey) {
Duck.apply(this);
this.oTurkey = oTurkey;
};
TurkeyAdapter.prototype = new Duck();
TurkeyAdapter.prototype.fly = function() {
// 调用火鸡的飞方法
this.oTurkey.fly();
};
// 让火鸡也有鸭子的方法
TurkeyAdapter.prototype.quack = function() {
this.oTurkey.gobble();
}
// 调用
var oMallardDuck = new MallardDuck();
oMallardDuck.fly(); // 可以飞翔很长的距离!
oMallardDuck.quack(); // 咯咯!咯咯! var oWildTurkey = new WildTurkey();
oWildTurkey.fly(); // 飞翔的距离貌似有点短!
oWildTurkey.gobble(); // 咯咯!咯咯! var oTurkeyAdapter = new TurkeyAdapter(oWildTurkey);
// 调用原有的火鸡的飞方法
oTurkeyAdapter.fly(); // 飞翔的距离貌似有点短!
// 调用鸭子特有的嘎嘎叫的方法 - 从而达到适配的目的
oTurkeyAdapter.quack(); // 咯咯!咯咯!

这样,有了TurkeyAdapter适配器,使得具体的实例对象oWildTurkey同样具有了Duck具有的方法quack。

  二、适用场景

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

  在这里,引入进大叔博客深入理解JavaScript系列(39):设计模式之适配器模式中适用场景的概括——

1.使用一个已经存在的对象,但其方法或属性接口不符合你的要求;
2.你想创建一个可复用的对象,该对象可以与其它不相关的对象或不可见对象(即接口方法或属性不兼容的对象)协同工作;
3.想使用已经存在的对象,但是不能对每一个都进行原型继承以匹配它的接口。对象适配器可以适配它的父对象接口方法或属性。

  三、优势

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

  四、劣势

  1.可能有些工程师不想使用适配器,其原因主要在于他们实际上需要彻底重写代码。有人认为适配器是一种不必要的开销,完全可以通过重写现有代码避免。
  2.适配器模式也会引入一批需要支持的新工具
  3.如果现有API还未定形,或者新接口还未定型(这更有可能),那么适配器可能不会一直管用。

  五、与其他模式的区别

  1.与门面模式的区别:从表面上看,适配器模式很像门面模式。它们都要对别的对象进行包装并改变其呈现的接口。二者的差别在于如何改变接口。门面元素展现的是一个简化的接口,它并不提供额外的选择,而且有时为了方便完成常见任务它还会做出一些假设。而适配器则要把一个接口转换为另一个接口,它并不会滤除某些能力,也不会简化接口。如果客户端系统期待的接口不可用,那就需要用到适配器。

  2.与桥接模式的区别:适配器和桥接模式虽然类似,但桥接的出发点不同,桥接的目的是将接口部分和实现部分分离,从而对他们可以更为容易也相对独立的加以改变。而适配器则意味着改变一个已有对象的接口。

  3.与装饰者模式的区别:装饰者模式增强了其它对象的功能而同时又不改变它的接口,因此它对应程序的透明性比适配器要好,其结果是装饰者支持递归组合,而纯粹使用适配器则是不可能的。

  4.与代理模式的区别:代理模式在不改变它的接口的条件下,为另外一个对象定义了一个代理。

  六、小结

  适配器模式是一种很有用的技术,它可以用来对类和对象进行包装,以便向客户代码提供其期待的接口。应用这种技术,你可以在不影响现有实现的前提下利用新的更好的接口。作为一个实现者,你可以根据自己的需要定制接口。这种模式的确会引入一些新代码,不过,在涉及大型系统和遗留框架的情况下,它的优点往往比缺点更突出。

源自:JavaScript设计模式(人民邮电出版社)——第十一章,适配器模式

参考:深入理解JavaScript系列(39):设计模式之适配器模式

【读书笔记】读《JavaScript设计模式》之适配器模式的更多相关文章

  1. 再起航,我的学习笔记之JavaScript设计模式12(适配器模式)

    适配器模式 适配器模式(Adapter): 将一个类(对象)的接口(方法或属性)转化成为另外一个接口,使类(对象)之间接口的不兼容问题通过适配器得以解决. 适配相似的框架 不知道大家有没有遇到过这种场 ...

  2. 读书笔记之 - javascript 设计模式 - 适配器模式

    适配器模式可以用来在现在接口和不兼容的类之间进行适配. 使用这种模式的对象又叫包装器,因为他们是在用一个新接口包装另一个对象. 在设计类的时候往往遇到有些接口不能与现有api一同使用的情况,借助于适配 ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. jsp学习(四)

    JavaBean是一个可重复使用的软件组件,是遵循一定标准.用java语言编写的一个类,该类的一个实例称为一个JavaBean,简称bean. 它必须符合如下规范:1.必须有一个零参数的默认构造函数2 ...

  2. c++实现gray code(格雷码)

    今天别人问的一道题,强调用分治法实现 =.= 百度了一下格雷码,然后写了一下. 关于格雷码大家看百度的吧,特别详细,贴个图: 代码如下(header_file.h是我自己写的一个头文件,包括常见的ve ...

  3. 多线程下载的原理&断点下载的原理

    1)多线程下载说明:

  4. hdu 2048 神、上帝以及老天爷

    经典错排问题,算出n个人的排列可能,即求n!. 在本题中设定所有人即n个人全部拍错,即求n错排. 要求:求出其全部错排发生的概率 n错排 / n! * 100  以小数形式输出即可. #include ...

  5. hdu 1201 18岁生日

    #include <stdio.h> int r(int y) { return (y%4==0&&y%100!=0)||(y%400==0); } int f(int y ...

  6. ios 关联对象运用 objc_setAssociatedObject

    点按钮的时候,给alertView添加一个关联对象(被点击这个按钮), objc_setAssociatedObject(alert, &kRepresentedObject, sender, ...

  7. 修复UIImagePickerController偷换StatusBar颜色的问题

    - (void)navigationController:(UINavigationController *)navigationController willShowViewController:( ...

  8. SQL语句修改表字段名/修改字段长度/增加字段/删除字段

    修改字段名Exec sp_rename 'zxchem_Suggest.End_Date','Yj_Finish_Date','Column' 修改字段长度Alter Table zxchem_Sug ...

  9. [LeetCode] Best Time to Buy and Sell Stock III

    将Best Time to Buy and Sell Stock的如下思路用到此题目 思路1:第i天买入,能赚到的最大利润是多少呢?就是i + 1 ~ n天中最大的股价减去第i天的. 思路2:第i天买 ...

  10. 如果jsp提交到action为空指针的话

    很严重的一点:表单<form>有没有添加一个method="post",如果表单的这个没有写,肯定是空指针, 哎,被这个坑爹的代码,查了好久,特此记录下