javascript设计模式-适配器模式

  1 DOCTYPE html>
  2 <html>
  3 <head>
  4     <title>title>
  5     <meta charset="utf-8">
  6 head>
  7 <body>
  8 <script>
  9 /**
 10  * 适配器模式
 11  *
 12  * 定义:
 13  * 将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
 14  *
 15  * 本质:
 16  * 转换匹配,复用功能
 17  *
 18  * 适配器模式可用来在现有接口和不兼容的类之间进行适配。使用这种模式的对象又叫包装器,因为它们是在用一个新的接口包装另一个对象。许多时候创建适配器对程序员和接口的设计人员都有好处。在设计类的时候往往会遇到有些接口不能与现有API一同使用的情况。借助于适配器,你不用直接修改这些类也能使用它们。在设计大型系统和遗留框架的情况下,他的优点往往比缺点更突出。
 19  *
 20  * 适配器的特点
 21  *
 22  * 适配器可以被添加到现有代码中以协调两个不同的接口。如果现有代码的接口能很好地满足需要,那就可能没有必要使用适配器。但要是现有接口对于手头的工作来说不够直观或实用,那么可以使用适配器来提供一个更简洁或更丰富的接口。
 23  * 从表面上看,适配器模式很像门面模式。它们都要对别的对象进行包装并改变其呈现的接口。二者的差别在于它们如何改变接口。门面元素展现的是一个简化的接口,它并不提供额外的选择,而且有时为了方便完成常见任务它还会做出一些假定。而适配器则要把一个接口转换为另一个接口,它并不会滤除某些能力,也不会简化接口。如果客户系统期待的API不可用,那就需要用到适配器。
 24  *
 25  * 应用适配器模式来解决问题的思路
 26  * 一般问题的根源在于接口的不兼容,功能是基本实现了,也就是说,只要让两边的接口匹配起来,就可以复用第一版的功能了。
 27  * 按照适配器模式的实现方式,可以定义一个类来实现第二版的接口,然后在内部实现的时候,转调第一版已经实现了的功能,这样就可以通过对象组合的方式,既复用了第一版已有的功能,同时又在接口上满足了第二版调用的需求,
 28  */
 29 
 30 // 例子
 31 // 已经存在的接口,这个接口需要被适配
 32 var Adaptee = function(){};
 33 Adaptee.prototype.specificRequest = function(){
 34     // 具体功能实现
 35 };
 36 
 37 // 适配器
 38 // 构造器,传入需要被适配的对象
 39 var Adapter = function(adaptee){
 40     this.adaptee = adaptee;
 41 };
 42 Adapter.prototype = {
 43     request: function(){
 44         // do sth
 45         // 可能转调已经实现了的方法,进行适配
 46         this.adaptee.specificRequest();
 47         // other thing
 48     }
 49 };
 50 
 51 var adaptee = new Adaptee();
 52 var target = new Adapter(adaptee);
 53 target.request();
 54 
 55 /*
 56 Adaptee和Target的关系
 57 
 58 适配器模式中被适配的接口Adaptee和适配成为的接口Target是没有关联的,也就是说,Adaptee和Target中的方法既可以相同,也可以不同。极端情况下两个接口里面的方法可能是完全不同的,也可能完全相同。
 59 
 60 对象组合
 61 
 62 适配器的实现方式其实是依靠对象组合的方式。通过给适配器对象组合被适配的对象,然后当客户端调用Target的时候,适配器会把相应的功能委托给被适配对象去完成。
 63 
 64 适配器模式的调用顺序
 65 
 66 target--Adapter--Adaptee
 67  */
 68 
 69 /*
 70 适配器的常见实现
 71 
 72 在实现适配器的时候,适配器通常是一个类,一般会让适配器类去实现Target接口,然后在适配器的具体实现里面调用Adaptee。也就是说适配器通常是一个Target类型,而不是Adaptee类型。
 73 
 74 智能适配器
 75 
 76 适配器也可以实现一些Adaptee没有实现,但是在Target中定义的的功能。这种情况就需要在适配器的实现里面,加入新功能的实现。这种适配器被称为智能适配器
 77 如果要使用智能适配器,一般新加入功能的实现会用到很多Adaptee的功能,相当于利用Adaptee的功能来实现更高层的功能。当然也可以完全实现新加入的功能,和已有的功能都不相关,变相地扩展了功能。
 78 
 79 适配多个Adaptee
 80 
 81 适配器在适配的时候,可以适配多个Adaptee,也就是说实现某个新的Target的功能的时候,需要调用多个模块的功能,适配多个模块的功能才能满足新接口的要求。
 82 
 83 适配器Adapter实现的复杂程度
 84 
 85 取决于Target和Adaptee的相似程度。
 86 
 87 缺省适配
 88 
 89 为一个接口提供缺省实现。有了它,就不用直接去实现接口,而是采用集成这个缺省适配对象,从而让子类可以有选择地去覆盖实现需要的方法,对于不需要的方法,使用缺省适配的方法就可以了。
 90 
 91 双向适配器
 92 
 93 适配器也可以实现双向的适配,既可以把Adaptee适配成为Target,也可以把Target适配成为Adaptee。也就是说这个适配器可以同时当作Target和Adaptee使用。
 94 在两个不同的客户需要用不用的方式查看同一个对象时,适合使用双向适配器。
 95 
 96  */
 97 
 98 /*
 99 对象适配器的实现: 依赖于对象的组合。。
100 
101 类适配器的实现: 采用多重继承对一个接口与另一个接口进行适配。
102  */
103 
104 /*
105  如果你有一个具有3个字符串参数的函数,但客户系统拥有的却是一个包含三个字符串元素的对象或数组,此时就可以用一个是配起来衔接二者。
106  */
107 var clientObject = {
108     string1: 'foo',
109     string2: 'bar',
110     string3: 'baz'
111 };
112 function interfaceMethod(str1, str2, str3) {
113     //...
114 }
115 // 适配器
116 function clientToInterfaceAdapter(o) {
117     interfaceMethod(o.string1, o.string2, o.string3);
118 }
119 clientToInterfaceAdapter(clientObject);
120 
121 
122 /*
123  适配原有实现
124 
125  在某些情况下,从客户一方对代码进行修改是不可能的。有些程序员因此索性避免创建API。如果现有接口发生了改变,那么客户代码也必须进行相应的修改后才能使用这个新接口,否则整个应用系统就有失灵的危险。在引入新接口之后,一般说来最好向客户方提供一些可为其实现新接口的适配器。
126  */
127 
128 // 示例:适配两个库
129 // 下面的例子要实现的是从Prototype库的$函数到YUI的get方法的转换
130 // 先看看他们在接口方面的差异
131 
132 // Prototype $ function
133 function $() {
134     var elements = [];
135     for (var i = 0; i < arguments.length; i++) {
136         var element = arguments[i];
137         if (typeof element === 'string') {
138             element = document.getElementById(element);
139         }
140         if (arguments.length === 1) {
141             return element;
142         }
143         elements.push(element);
144     }
145     return elements;
146 }
147 
148 // YUI get method
149 YAHOO.util.Dom.get = function (el) {
150     if (YAHOO.lang.isString(el)) {
151         return document.getElementById(el);
152     }
153     if (YAHOO.lang.isArray(el)) {
154         var c = [];
155         for (var i = 0, len = el.length; i < len; ++i) {
156             c[c.length] = YAHOO.util.Dom.get(el[i]);
157         }
158         return c;
159     }
160     if (el) {
161         return el;
162     }
163     return null;
164 };
165 
166 // Adapter
167 function PrototypeToYUIAdapter() {
168     return YAHOO.util.Dom.get(arguments);
169 }
170 function YUIToPrototypeAdapter(el) {
171     return $.apply(window, el instanceof Array ? el : [el]);
172 }
173 
174 // 有了这些适配器,现有的客户系统就可以继续使用其熟悉的API。
175 $ = PrototypeToYUIAdapter;
176 // or
177 YAHOO.util.Dom.get = YUIToPrototypeAdapter;
178 
179 
180 // 示例:适配电子邮件API
181 /*
182  本例研究的是一个web邮件API,它可以用来接收,发送邮件并执行一些别的任务。我们将采用类Ajax技术从服务器或取消息,然后将消息详情载入DOM。
183  */
184 /*
185  
186  
187  
188  Mail API Demonstration
189  
190  
200  
201  
202  
203

Email Application Interface

204 209
210
211 212

你可能感兴趣的:(javascript设计模式-适配器模式)