1. 程式人生 > >精通JavaScript--06設計模式:結構型

精通JavaScript--06設計模式:結構型

bsp sin callback 時有 入參 遍歷 toupper 出現 state

本章主要學習結構性設計模式,前一章介紹的創建型設計模式側重於對象的處理,而結構型設計模式則有助於把多個對象整合為一個更大型的、更有組織的代碼庫。它們具有靈活性,可維護性,可擴展性,並能夠確保當系統中的某一部分發生變更時,不必完全重寫其余部分進行適應。結構型模式還可用於幫助我們與其他代碼結構(在我們的應用程序中需要簡易地實現與這些代碼結構的協同運作)

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演示了一個例子,當中創建了若幹裝飾者,每個裝飾者都會對一個已存在的對象增加額外的屬性和行為。

精通JavaScript--06設計模式:結構型