免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2040 | 回复: 0
打印 上一主题 下一主题

设计模式_command模式 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-12-01 10:29 |只看该作者 |倒序浏览

                1.什么时候使用command模式
   1、使用命令模式作为"CallBack"在面向对象系统中的替代。"CallBack"讲的便是先将一个函数登记上,然后在以后调用此函数。
   2、需要在不同的时间指定请求、将请求排队。一个命令对象和原先的请求发出者可以有不同的生命期。换言之,原先的请求发出者可能已经不在了,而命令对象本身仍然是活动的。这时命令的接收者可以是在本地,也可以在网络的另外一个地址。命令对象可以在串形化之后传送到另外一台机器上去。
   3、系统需要支持命令的撤消(undo)。命令对象可以把状态存储起来,等到客户端需要撤销命令所产生的效果时,可以调用undo()方法,把命令所产生的效果撤销掉。命令对象还可以提供redo()方法,以供客户端在需要时,再重新实施命令效果。
   4、如果一个系统要将系统中所有的数据更新到日志里,以便在系统崩溃时,可以根据日志里读回所有的数据更新命令,重新调用Execute()方法一条一条执行这些命令,从而恢复系统在崩溃前所做的数据更新。
   5、一个系统需要支持交易(Transaction)。一个交易结构封装了一组数据更新命令。使用命令模式来实现交易结构可以使系统增加新的交易类型。
2.command模式的几个要素
   命令模式又称为行动(Action)模式或交易(Transaction)模式。命令模式把一个请求或者操作封装到一个对象中。命令模式允许系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
   命令模式涉及到五个角色,它们分别是:
      客户(Client)角色:创建了一个具体命令(ConcreteCommand)对象并确定其接收者。
      命令(Command)角色:声明了一个给所有具体命令类的抽象接口。这是一个抽象角色。
      具体命令(ConcreteCommand)角色:定义一个接受者和行为之间的弱耦合;实现Execute()方法,负责调用接收考的相应操作。Execute()方法通常叫做执方法。
      请求者(Invoker)角色:负责调用命令对象执行请求,相关的方法叫做行动方法。
      接收者(Receiver)角色:负责具体实施和执行一个请求。任何一个类都可以成为接收者,实施和执行请求的方法叫做行动方法。

     协作说明:
     客户端创建了一个具体的Command对象并指定了其接收者。调用者对象存储了此具体的Command对象。调用者对象通过执行Command对象的 Execute方法来实现当前请求。如果命令是可以撤销时,具体对象在调用执行方法前将存储相应的状态以用来命令此请求。具体的Command对象调用其接收者的方法从而来实现相应请求。
3.代码举例
public class CommandDemo {
    public static void main(String[] args) {
        Reciver reciver = new Reciver();//有个人能执行某个命令,各尽其能
        Command command = new ConcreteCommand(receiver);//领导将这个人与这个命令绑定,一但要执行这个命令,就找他,人尽其用
        Invoker invoker= new Invoker();//负责什么时候传达命令,而且还不用管是什么命令,相当于管家,只管传令
        Invoker.add(command);//领导让他传达一个命令
        Invoker.action();//他就开始传达
    }
}
public interface Command {
    public void execute();
}
public class ConcreteCommand implements Command {
    Reciver reciver;
    /**
     * 需命令的真正实现者即reciever
     *
     * @param programer
     */
    public ConcreteCommand(Reciver reciver) {
        this.reciver= reciver;
    }
    public void execute() {
        reciver.doing();
    }
}
public class Reciver {
    /**
     * reciver是具体需求的真正执行者
     */
    public void doing() {
        System.out.println("design...coding...test...shell out");
    }
}
public class Invoker{
    private Command cmd;
    public void add(Command cmd) {
        this.cmd = cmd;
    }
    /**
     * 对于命令模式而言,它只需知道启动命令的执行既可,与真正的实现者解耦 且此处使用的是Command接口
     */
    public void action() {
        cmd.execute();
    }
}
   命令模式有如下的一些好处:
        1:命令模式将调用者对象与接收对象解耦(调用与实现解耦)。调用者实现功能时只需调用Command接口的Execute方法。
        2:具体的Commands对象是第一层对象,它们可以像其他对象一样被扩展或继承。
        3:你可以将多个Commands对象聚合成一个组合命令。组合命令也是组合对象模式的一个实例,将命令排队也是其的一种特殊情况。
        4:你可以很容易的添加新的命令,因为你并不需要修改现有的代码。这也符合了开闭原则,对修改关闭,对扩展开放。
4.命令模式应用举例
4.1玉帝传美猴王上天
    命令模式不是新的发明,在美猴王大闹天宫之前就有了。那时玉帝命令太白金星召美猴王上天:"金星径入(水帘洞)当中,面南立定道:'我是西方太白金星,奉玉帝招安圣旨,下界请你上大,拜受仙录。'"玉帝是系统的客户端,太白金星是命令的发出者,猴王是命令的接收者,圣旨就是命令。玉帝的这一道命令就是要求猴王到上界报到。玉帝只管发出命令,而不管命令是怎样传达到美猴王的。太白金星负责将圣旨传到,可是美猴王怎么执行圣旨、何时执行圣旨是美猴王自己的事。果不然,个久美猴王就大闹了天宫。
这个模拟系统的设计如下:

4.2使用命令模式演示了一个简单的计算器,并允许执行undo与redo
   注意:"operator"在C#中是关键词,所以在前面添加一个"@"将其变为标识符。
   1. // Command pattern -- Real World example 
   2. using System;
   3. using System.Collections;
   4. // "Command"
   5. abstract class Command
   6. {
   7.  // Methods
   8.  abstract public void Execute();
   9.  abstract public void UnExecute();
  10. }
  11. // "ConcreteCommand"
  12. class CalculatorCommand : Command
  13. {
  14.  // Fields
  15.  char @operator;
  16.  int operand;
  17.  Calculator calculator;
  18.  // Constructor
  19.  public CalculatorCommand( Calculator calculator,
  20.   char @operator, int operand )
  21.  {
  22.   this.calculator = calculator;
  23.   this.@operator = @operator;
  24.   this.operand = operand;
  25.  }
  26.  // Properties
  27.  public char Operator
  28.  {
  29.   set{ @operator = value; }
  30.  }
  31.  public int Operand
  32.  {
  33.   set{ operand = value; }
  34.  }
  35.  // Methods
  36.  override public void Execute()
  37.  {
  38.   calculator.Operation( @operator, operand );
  39.  }
  40.  
  41.  override public void UnExecute()
  42.  {
  43.   calculator.Operation( Undo( @operator ), operand );
  44.  }
  45.  // Private helper function
  46.  private char Undo( char @operator )
  47.  {
  48.   char undo = ' ';
  49.   switch( @operator )
  50.   {
  51.    case '+': undo = '-'; break;
  52.    case '-': undo = '+'; break;
  53.    case '*': undo = '/'; break;
  54.    case '/': undo = '*'; break;
  55.   }
  56.   return undo;
  57.  }
  58. }
  59. // "Receiver"
  60. class Calculator
  61. {
  62.  // Fields
  63.  private int total = 0;
  64.  // Methods
  65.  public void Operation( char @operator, int operand )
  66.  {
  67.   switch( @operator )
  68.   {
  69.    case '+': total += operand; break;
  70.    case '-': total -= operand; break;
  71.    case '*': total *= operand; break;
  72.    case '/': total /= operand; break;
  73.   }
  74.   Console.WriteLine( "Total = {0} (following {1} {2})",
  75.    total, @operator, operand );
  76.  }
  77. }
  78. // "Invoker"
  79. class User
  80. {
  81.  // Fields
  82.  private Calculator calculator = new Calculator();
  83.  private ArrayList commands = new ArrayList();
  84.  private int current = 0;
  85.  // Methods
  86.  public void Redo( int levels )
  87.  {
  88.   Console.WriteLine( "---- Redo {0} levels ", levels );
  89.   // Perform redo operations
  90.   for( int i = 0; i  0 )
100.     ((Command)commands[ --current ]).UnExecute();
101.  }
102.  public void Compute( char @operator, int operand )
103.  {
104.   // Create command operation and execute it
105.   Command command = new CalculatorCommand(
106.    calculator, @operator, operand );
107.   command.Execute();
108.   // Add command to undo list
109.   commands.Add( command );
110.   current++;
111.  }
112. }
113. /**////
114. /// CommandApp test
115. ///
116. public class Client
117. {
118.  public static void Main( string[] args )
119.  {
120.   // Create user and let her compute
121.   User user = new User();
122.   user.Compute( '+', 100 );
123.   user.Compute( '-', 50 );
124.   user.Compute( '*', 10 );
125.   user.Compute( '/', 2 );
126.   // Undo and then redo some commands
127.   user.Undo( 4 );
128.   user.Redo( 3 );
129.  }
130. }
5.命令模式的优点和缺点
优点:
   命令模式使新的命令很容易地被加入到系统里。
   允许接收请求的一方决定是否要否决(Veto)请求。
   能较容易地设计一个命令队列。
   可以容易地实现对请求的Undo和Redo。
   在需要的情况下,可以较容易地将命令记入日志。
   命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分割开。
   命令类与其他任何别的类一样,可以修改和推广。
   你可以把命令对象聚合在一起,合成为合成命令。比如宏命令便是合成命令的例子。合成命令是合成模式的应用。
   由于加进新的具体命令类不影响类,因此增加新的具体命令类很容易。
缺点:
   使用命令模式会导致某些系统有过多的具体命令类。某些系统可能需要几十个,几百个甚至几千个具体命令类,这会使命令模式在这样的系统里变得不实际。
参考文献:
1.设计模式之Command设计模式. http://www.uml.org.cn/sjms/200904151.asp
2.设计模式之命令模式-Command pattern. http://www.emlog.net/fei/post-67.html
               
               
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/21752/showart_2107995.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP