JS與設計模式之------命令模式Command

來源:互聯網
上載者:User

JS與設計模式之------命令模式Command
先給個具體案例,如下:   1 function add(x, y) { return x + y; } ; 2 function sub(x, y) { return x - y; } ; 3 function mul(x, y) { return x * y; } ; 4 function div(x, y) { return x / y; } ; 5   6 var Command = function (execute, undo, value) { 7     this.execute = execute; 8     this.undo = undo; 9     this.value = value;10 }11  12 var AddCommand = function (value) {13     return new Command(add, sub, value);14 };15  16 var SubCommand = function (value) {17     return new Command(sub, add, value);18 };19  20 var MulCommand = function (value) {21     return new Command(mul, div, value);22 };23  24 var DivCommand = function (value) {25     return new Command(div, mul, value);26 };27  28 var Calculator = function () {29     var current = 0;30     var commands = [];31  32     function action(command) {33         var name = command.execute.toString().substr(9, 3);34         return name.charAt(0).toUpperCase() + name.slice(1);35     }36  37     return {38         execute: function (command) {39             current = command.execute(current, command.value);40             commands.push(command);41             log.add(action(command) + ": " + command.value);42         },43  44         undo: function () {45             var command = commands.pop();46             current = command.undo(current, command.value);47             log.add("Undo " + action(command) + ": " + command.value);48         },49  50         getCurrentValue: function () {51             return current;52         }53     }54 }55 56 var log = (function () {57     var log = "";58  59     return {60         add: function (msg) { log += msg + "\n"; },61         show: function () { alert(log); log = ""; }62     }63 })();64  65 function run() {66     var calculator = new Calculator();67     calculator.execute(new AddCommand(100));68     calculator.execute(new SubCommand(24));69     calculator.execute(new MulCommand(6));70     calculator.execute(new DivCommand(2));71     calculator.undo();72     calculator.undo();73     log.add("\nValue: " + calculator.getCurrentValue());74     log.show();75 } 這是一個計算機的例子,將每一個具體操作以對象的形式進行封裝,計算機接收到我們的請求後, 對發出具體的命令,是+,-,還是*/。這樣,我們把請求傳給計算機,計算機來具體執行需要哪些命令。 這樣一來雖然結果是一樣的,都是計算出結果,但是過程去截然不同嘍。最大限度的降低了耦合。   二,源碼案例參考   在命令模式的總體思路是,它給我們提供一種分開的任何執行命令發布命令的責任,這種責任的不同對象而不是授權。 簡單的命令對象結合在一起的一種行為對象要調用動作。他們始終包括一個執行操作(如run()或execute())。所有的命令對象具有相同的介面,可以很容易地被交換的需要。   三,案例引入   具體的Command模式代碼各式各樣,因為如何封裝命令,不同系統,有不同的做法。下面案例是將命令封裝在一個List中,任何對象一旦加入List中,實際上裝入了一個封閉的黑盒中,對象的特性消失了,只有取出時,才有可能模糊的分辨出: 典型的Command模式需要有一個介面,介面中有一個統一的方法,這就是"將命令/請求封裝為對象"。 (1) ,建立程式猿實體類 1 function Programmer(){2     this.execute = function(){3         console.log("程式猿寫代碼!") ;4     } ;5 } ;  (2) ,建立工程師實體類 1 function Engineer(){2     this.execute = function(){3         console.log("工程師蓋房子!") ;4     } ;5 } ;  (3) ,建立政治家實體類 1 function Politician(){2     this.execute = function(){3         console.log("政治家噴人!") ;4     } ;5 } ;  (4) ,建立黑盒子類 按照通常做法,我們就可以直接調用這三個Command,但是使用Command模式,我們要將他們封裝起來,扔到黑盒子List裡去:   1 function Producer(){ 2     var list = [] ; 3     return { 4         produceRequests : function(){ 5             list.push(new Engineer()) ; 6             list.push(new Programmer()) ; 7             list.push(new Politician()) ; 8             return list ; 9         }10     }11 } 這三個命令進入List中後,已經失去了其外表特徵,以後再取出,也可能無法分辨出誰是Engineer,誰是Programmer了,看下面用戶端如何調用Command模式: (5) ,建立命令用戶端類 1 function CMDClient(){2     var cmdlist = Producer.produceRequests() ;3     for(var p in cmdlist){4         (cmdlist[p]).execute() ;5     }6 } ;理解了上面的代碼的核心原理,在使用中,就應該各人有自己方法了,特別是在如何分離調用者和具體命令上,有很多實現方法,上面的代碼是使用"從List過一遍"的做法.這種做法只是為了示範.   使用Command模式的一個好理由還因為它能實現Undo功能.每個具體命令都可以記住它剛剛執行的動作,並且在需要時恢複.     四,總結一下   命令具有以下的優點:   (1)命令模式使新的命令很容易地被加入到系統裡。   (2)允許接收請求的一方決定是否要否決請求。   (3)能較容易地設計一個命令隊列。   (4)可以容易地實現對請求的撤銷和恢複。   (5)在需要的情況下,可以較容易地將命令記入日誌。    更鬆散的耦合    命令模式使得發起命令的對象——用戶端,和具體實現命令的對象——接收者對象完全解耦,也就是說發起命令的對象完全不知道具體實現對象是誰,也不知道如何?。    更動態控制    命令模式把請求封裝起來,可以動態地對它進行參數化、隊列化和日誌化等操作,從而使得系統更靈活。    很自然的複合命令    命令模式中的命令對象能夠很容易地組合成複合命令,也就是宏命令,從而使系統操作更簡單,功能更強大。    更好的擴充性   由於發起命令的對象和具體的實現完全解耦,因此擴充新的命令就很容易,只需要實現新的命令對象,然後在裝配的時候,把具體的實現對象設定到命令對象中,然後就可以使用這個命令對象,已有的實現完全不用變化。     應用情境     1)使用命令模式作為"CallBack"在物件導向系統中的替代。"CallBack"講的便是先將一個函數登記上,然後在以後調用此函數。     2)需要在不同的時間指定請求、將請求排隊。一個命令對象和原先的請求發出者可以有不同的生命期。換言之,原先的請求發出者可能已經不在了,而命令對象本身仍然是活動的。這時命令的接收者可以是在本地,也可以在網路的另外一個地址。命令對象可以在串形化之後傳送到另外一台機器上去。     3)系統需要支援命令的撤消(undo)。命令對象可以把狀態儲存起來,等到用戶端需要撤銷命令所產生的效果時,可以調用undo()方法,把命令所產生的效果撤銷掉。命令對象還可以提供redo()方法,以供用戶端在需要時,再重新實施命令效果。     4)如果一個系統要將系統中所有的資料更新到日誌裡,以便在系統崩潰時,可以根據日誌裡讀回所有的資料更新命令,重新調用Execute()方法一條一條執行這些命令,從而恢複系統在崩潰前所做的資料更新。  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.