JS与设计模式之------命令模式Command

页面导航:首页 > 网络编程 > JavaScript > JS与设计模式之------命令模式Command

JS与设计模式之------命令模式Command

来源: 作者: 时间:2016-02-04 09:15 【

先给个具体事例,如下: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)
先给个具体事例,如下:
 
 
 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()方法一条一条执行这些命令,从而恢复系统在崩溃前所做的数据更新。
 
 
Tags:

文章评论

最 近 更 新
热 点 排 行
Js与CSS工具
代码转换工具

<