精通JavaScript--06设计模式:结构型

本章主要学习结构性设计模式,前一章介绍的创建型设计模式侧重于对象的处理,而结构型设计模式则有助于把多个对象整合为一个更大型的、更有组织的代码库。它们具有灵活性,可维护性,可扩展性,并能够确保当系统中的某一部分发生变更时,不必完全重写其余部分进行适应。结构型模式还可用于帮助我们与其他代码结构(在我们的应用程序中需要简易地实现与这些代码结构的协同运作)

6.1  适配器模式

适配器(adapter)模式是一种很有用的设计模式。当需要关联两个或更多代码组件时便可应用此模式,否则这些代码将无法正常关联在一起。相类似地,当一个你之前开的API出现更新而不能再按相同的方法进行调用时,此模式也能帮上大忙。适配器提供了旧版本与新版本API之间的对接,能够帮助那些使用你的API的用户迁移至新API,使得用户在分享你改进后的代码的同时而又不必更改其原来的旧代码。代码清单6-1演示了如果使用此模式来为代码创建一个适配器,以将新的API映射至旧API。

  1             //假设以下节课深藏在你庞大的代码库中,用于通过HTTP发出Ajax请求
  2             var http = {
  3                 makeRequest: function(type, url, callback, data) {
  4                     var xhr = new XMLHttpRequest(),
  5                         STATE_LOADED = 4,
  6                         STATUS_OK = 200;
  7
  8                     xhr.onreadystatechange = function() {
  9                         if(xhr.readyState !== STATE_LOADED) {
 10                             return;
 11                         }
 12
 13                         if(xhr.status === STATUS_OK) {
 14                             callback(xhr.responseText);
 15                         }
 16                     };
 17                     xhr.open(type.toUpperCase(), url);
 18                     xhr.send(data);
 19                 }
 20             };
 21
 22             //以上定义的http.makeRequest()方法可按如下方式进行调用,以对系统中的ID为“12345”的用户的数据进行获取和更新
 23             http.makeRequest("get", "/user/12345", function(response) {
 24                 alert("HTTP GET response received,User data:" + response);
 25             });
 26
 27             http.makeRequest("post", "/user/12345", function(response) {
 28                 alert("HTTP POST response received,New User data:" + response);
 29             }, "company=AKQA&name=wing");
 30
 31             //现在,假设你要对项目进行重构,你决定引入一个新的结构,使用命名空间,并把makeRequest()方法划分为
 32             //两个独立的方法来发出HTTP GET和POST请求
 33             var myProject = {
 34                 data: {
 35                     ajax: (function() {
 36                         function createRequestObj(callback) {
 37                             var xhr = new XMLHttpRequest(),
 38                                 STATE_LOADED = 4,
 39                                 STATUS_OK = 200;
 40                             xhr.onreadystatechange = function() {
 41                                 if(xhr.readyState !== STATE_LOADED) {
 42                                     return;
 43                                 }
 44
 45                                 if(xhr.status === STATUS_OK) {
 46                                     callback(xhr.responseText);
 47                                 }
 48                             };
 49                             return xhr;
 50                         }
 51                         return {
 52                             get: function(url, callback) {
 53                                 var requestObj = createRequestObj(callback);
 54                                 requestObj.open("GET", url);
 55                                 requestObj.send();
 56
 57                             },
 58                             post: function(url, data, callback) {
 59                                 var requestObj = createRequestObj(callback);
 60                                 requestObj.open("POST", url);
 61                                 requestObj.send(data);
 62                             }
 63
 64                         };
 65                     }())
 66                 }
 67             };
 68
 69             //新的get()和post()方法可按如下方式调用
 70             myProject.data.ajax.get("/user/12345",function(response){
 71                 alert("Refactored HTTP GET response received.User data:"+response);
 72             });
 73
 74             myProject.data.ajax.post("/user/12345","company=AKQA&name=wing",function(response){
 75                 alert("Refactored HTTP GET response received.New User data:"+response);
 76             });
 77
 78             //为了避免在代码库中的其余部分重写每一个对http.makeRequest()方法的调用,你可以创建一个适配器来映射
 79             //旧接口至新方法。配置器需要使用与所要替换掉的原方法相同的输入参数,并在适配器内部调用新方法
 80             function httpToAjaxAdapter(type,url,callback,data){
 81                 if(type.toLowerCase()==="get"){
 82                     myProject.data.ajax.get(url,callback);
 83                 }else if(type.toLowerCase()==="post"){
 84                     myProject.data.ajax.post(url,data,callback);
 85                 }
 86             }
 87
 88             //最后,应用配置器来代替员原来的方法
 89             //这样,它将会映射旧接口至新方法,而不需要同时重写整个代码的其余部分
 90             http.makeRequest=httpToAjaxAdapter;
 91
 92             //按照原方法的使用方式使用该新的适配器————在内部,它将调用新的代码,但在外部,
 93             //它看起来有与旧的makeRequest()方法一模一样
 94             http.makeRequest("get","/user/123456",function(response){
 95                 alert("Refactored HTTP GET response received.User data:"+response);
 96             });
 97
 98             http.makeRequest("post","/user/12345",function(response){
 99                 alert("Refactored HTTP GET response received.New User data:"+response);
100             },"company=AKQA&name=wing");

当需要把不同的代码进行关联,否则这些代码无法兼容在一起工作时,使用适配器模式最为合适。例如,当某个外部API进行了更新时,可以创建一个是适配器来映射各新方法至旧方法,以避免更改依赖这些方法的其余代码。

6.2  组合模式

组合(composite)模式为一个或多个对象创建了一个接口,使终端用户不需要知道他们所处里对象的个数。当你希望能够简化其他开发者对你的函数的访问方法时,该模式很有帮助。无论他人向同一方法传入的是一个单独对象还是一个由对象组成的数组,都不需要区别对待。代码清单6-2展示了组合模式的一个简单例子。用户可以添加class标签特性名称至一个或多个DOM节点,而不需要知道是否应将一个或多个DOM节点传给该方法。

代码清单6-2  组合模式

 1     var elements = {
 2                 //定义一个方法按tag名称获取DOM元素。如果只发现一个元素,则它作为一个单独的节点返回,
 3                 //如果发现多个元素,则返回这些元素所组成的数组
 4                 get: function(tag) {
 5                     var elems = document.getElementsByTagName(tag),
 6                         elemsIndex = 0,
 7                         elemsLength = elems.length,
 8                         output = [];
 9
10                     //把所找到的元素结构转化为一个标准数组
11                     for(; elemsIndex < elemsLength; elemsIndex++) {
12                         output.push(elems[elemsIndex]);
13                     }
14                     //如果只找到一个元素,则返回该独立元素,否则返回所找到的各个元素所组成的数组
15                     return output.length === 1 ? output[0] : output;
16                 },
17
18                 //定义一个组合方法,用于为一个或多个元素添加class标签特性class名称,无论在执行时有多少个元素被传入都可实现
19                 addClass: function(elems, newClassName) {
20                     var elemIndex = 0,
21                         elemLength = elems.length,
22                         elem;
23
24                     //判断所传入的元素究竟是数组还是一个单独对象
25                     if(Object.prototype.toString.call(elems) === "[object Array]") {
26                         //如果是数组,循环遍历每一个元素并为每个元素都增加class标签特性class名称
27                         for(; elemIndex < elemLength; elemIndex++) {
28                             elem = elems[elemIndex];
29                             elem.className += (elem.className === "" ? "" : " ") + newClassName;
30                         }
31                     } else {
32                         //如果传入的是单独元素,则为其增加class标签特性class名称值
33                         elems.className += (elems.className === "" ? "" : " ") + newClassName;
34                     }
35                 }
36             };
37
38             //使用该elements.get()方法来找出当前页面的单独的<body>元素,已经<a>元素(可能有很多个)
39             var body = elements.get("body"),
40                 links = elements.get("a");
41
42             //该组合方式elements.addClass()为单独元素和多个元素给出了相同的使用接口,很明显地简化了该方法的使用
43             elements.addClass(body, "has-js");
44             elements.addClass(links, "custom-link");

若不希望那些正与你的方法进行交互的开发者操心需要传入多少个对象作为方法参数,使用组合模式最为合适,这样可以简化方法的调用。

6.3  装饰模式

装饰(decorator)模式用于为某个“类”创建的对象扩展和定制额外的方法和属性,避免了因创建大量的子类而变得难以维护。其实现方法时,通过有效地将对象包装在另一个对象中,此另一个对象实现了相同的公共方法,根据我们所要增加的行为对相关方法进行重写。

代码清单6-3演示了一个例子,当中创建了若干装饰者,每个装饰者都会对一个已存在的对象增加额外的属性和行为。

时间: 2024-08-03 00:24:26

精通JavaScript--06设计模式:结构型的相关文章

设计模式——结构型模式

设计模式的另一大类型为结构型.共收录了7个模式,分别为适配器模式.桥接模式.组合模式.装饰模式.外观模式.享元模式.代理模式.下面从特点和使用两方面小探,欢迎交流!      适配器模式(Adapter):将一个类的接口转换成客户希望的另外一个接口.Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作.[大话设计模式]        特点:需要交流的两方,在数据和行为都匹配,但接口不符时,我们应该考虑用适配器,目的是促使交流和复用.可以理解为入乡随俗,相同的意思,不同的表达

设计模式(结构型)之外观模式(Facade Pattern)

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbober] 阅读前一篇<设计模式(结构型)之装饰者模式(Decorator Pattern)>http://blog.csdn.net/yanbober/article/details/45395747 概述 一个客户类需要和多个业务类交互,而这些业务类经常会作为整体出现,由于涉及到的类比较多,导致使

设计模式(结构型)之代理模式(Proxy Pattern)

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbober] 阅读前一篇<设计模式(结构型)之享元模式(Flyweight Pattern)>http://blog.csdn.net/yanbober/article/details/45477551 概述 代理模式是常用的结构型设计模式之一,当无法直接访问某个对象或访问某个对象存在困难时可以通过一个

设计模式(结构型)之装饰者模式(Decorator Pattern)

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbober] 阅读前一篇<设计模式(结构型)之组合模式(Composite Pattern)>http://blog.csdn.net/yanbober/article/details/45392513 概述 装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为.装饰模式是一种用于替代继承

设计模式(结构型)之组合模式(Composite Pattern)

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbober] 阅读前一篇<设计模式(结构型)之桥接模式(Bridge Pattern)> http://blog.csdn.net/yanbober/article/details/45366781 概述 组合模式又叫做部分-整体模式,使我们在树型结构的问题中模糊简单元素和复杂元素的概念,客户程序可以像

设计模式(结构型)之享元模式(Flyweight Pattern)

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbober] 阅读前一篇<设计模式(结构型)之外观模式(Facade Pattern)>http://blog.csdn.net/yanbober/article/details/45476527 概述 当一个软件系统在运行时产生的对象数量太多,将导致运行代价过高,带来系统性能下降等问题.所以需要采用一

设计模式-结构型模式,适配器模式(4)

适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁.这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能. 这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能.举个真实的例子,读卡器是作为内存卡和笔记本之间的适配器.您将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡. #!/usr/bin/env python # encoding: utf-8 class Target(object): def request(self

设计模式-结构型模式,python组合模式

设计模式上大的方向上分继承和组合,就是类模式和对象模式.此篇的组合模式非继承和组合概念中的组合.桥接 策略 代理 装饰者都用了组合,此组合非彼组合. 组合模式 组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象.组合模式依据树形结构来组合对象,用来表示部分以及整体层次.这种类型的设计模式属于结构型模式,它创建了对象组的树形结构. 这种模式创建了一个包含自己对象组的类.该类提供了修改相同对象组的方式. 我们通过下面的实例来演示组合模式的用法.

看透设计模式-结构型模式

这里我们主要讨论 结构型模式 适配器模式,: ● Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类. ● Adapter(适配器类):适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系. ● Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,

设计模式-结构型

一. 适配器模式 配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁.这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能.这个模式将一个类的接口转换成客户希望的另外一个接口.适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 实现方式是,适配器继承或依赖已有的对象,实现想要的目标接口. 需要注意的是: 适配器不是在详细设计时添加的,而是解决正在服役的项目的问题. 二. 桥接模式 桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变