iT邦幫忙

DAY 11
4

Javascript面面觀系列 第 11

Javascript面面觀:核心篇《模式-decorator》

  • 分享至 

  • xImage
  •  

Decorator很好用,不過我初次接觸時就搞不太懂什麼叫做「一次增加一點職責」,感覺很抽象。不過後來使用過幾個Java中的I/O類別就明白了,它真的很好用,而且有彈性,耦合也低。
結構
GOF的Decorator模式,需要用兩個方法做出來,一個是要有一致的操作,這樣才能把多個操作串接起來;另外一個是要用Constructor來把要串接的物件串接起來,這樣語法才會簡潔。

簡單的decorator大概像這樣:

 <script>
 function base (str) {
 	this._str = str;
 	this.render = function() {
 		return this._str;
 	};
 }
 function decorator1 (obj) {
 	this._obj = obj;
 	this.render = function () {
 		return "{" + this._obj.render() + "}";
 	};
 }
 function decorator2 (obj) {
 	this._obj = obj;
 	this.render = function () {
 		return "[" + this._obj.render() + "]";
 	};
 }
 function decorator3 (obj) {
 	this._obj = obj;
 	this.render = function () {
 		return "(" + this._obj.render() + ")";
 	};
 }
 var a = new decorator3(
 		new decorator2(
 			new decorator1(
 				new base("this is a base for other decorator.")
 			)
 		)
 	);
 alert(a.render());
 </script>
 
 

他的好處就是可以視需要再加以組合,每一個decorator都只加上一點「裝飾」。依照組合的順序,就會做出不同的效果。

應用
我自己曾經把它拿來做decoder的組合,例如用ajax從伺服器取到的是一個編碼過的字串,解碼過會是一個CSV格式的字串,然後還需要把它解碼成陣列。額外的需求是編碼方法會變動,CSV格式可能也會有調整,所以基於滿足這些彈性的需求,我用Decorator來把這個過程實作出來。

以下是一個簡單的範例(我沒有把真正實作細節的程式放進去,所以請用想像力了):

 var Parser = {
     base64Parser: {
         encode: function(str){return encoded_str;},
         decode: function(str){return decoded_str;}
     },
     escapeParser: {
         encode: function(str){return encoded_str;},
         decode: function(str){return decoded_str;}
     },
     AESParser: {
         encode: function(str,key){return encoded_str;},
         decode: function(str,key){return decoded_str;}
     },
     CSVParser = {
         encode: function(arr){return encoded_str;},
         decode: function(str){return decoded_arr;}
     }
     CSV1Parser = {
         encode: function(arr){return encoded_str;},
         decode: function(str){return decoded_arr;}
     }
 };
 var Reader = {
     base: function(path){
         this.read = function() {
             return $.ajax(path).responseText;
         };
     },
     base64Reader: function(obj) {
         var _obj = obj;
         this.read = function() {
             return Parser.base64Parser.decode(obj.read());
         };
     },
     escapeReader: function(obj) {
         var _obj = obj;
         this.read = function() {
             return Parser.escapeParser.decode(obj.read());
         };
     },
     AESReader: function(obj, key) {
         var _obj = obj;
         this.read = function() {
             return Parser.AESParser.decode(obj.read(), key);
         };
     },
     CSVReader: function(obj) {
         var _obj = obj;
         this.read = function() {
             return Parser.CSVParser.decode(obj.read());
         };
     },
     CSV1Reader: function(obj) {
         var _obj = obj;
         this.read = function() {
             return Parser.CSV1Parser.decode(obj.read());
         };
     },
 };

在使用上,就依照需求適當組合就可以使用,例如伺服器提供的是一個base64編碼字串,解碼成的csv格式需要用CSVParser解碼,那可以這樣用:

 var arr = new CSVReader(
     new base64Reader(
         new base('http://localhost/dataprovider.php?id=xxx')
     )
 );
 var data = new ArrayDataStore(arr.read());

如果伺服器端改成用AES編碼,那只要調一下:

 var arr = new CSVReader(
     new AESReader(
         new base('http://localhost/dataprovider.php?id=xxx'), key
     )
 );
 var data = new ArrayDataStore(arr.read());

這樣,即使不必為未來的需求做太多設計,系統也可以有彈性應付。


上一篇
Javascript面面觀:核心篇《模式-singleton》
下一篇
Javascript面面觀:核心篇《模式-Reflection, Proxy and AOP》
系列文
Javascript面面觀30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言