程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C#設計模式之Command設計模式(命令設計模式)(3)

C#設計模式之Command設計模式(命令設計模式)(3)

編輯:關於C語言

四、玉帝傳美猴王上天

命令模式不是新的發明,在美猴王大鬧天宮之前就有了。那時玉帝命令太白金星召美猴王上天:"金星徑入(水簾洞)當中,面南立定道:'我是西方太白金星,奉玉帝招安聖旨,下界請你上大,拜受仙錄。'"玉帝是系統的客戶端,太白金星是命令的發出者,猴王是命令的接收者,聖旨就是命令。玉帝的這一道命令就是要求猴王到上界報到。玉帝只管發出命令,而不管命令是怎樣傳達到美猴王的。太白金星負責將聖旨傳到,可是美猴王怎麼執行聖旨、何時執行聖旨是美猴王自己的事。果不然,個久美猴王就大鬧了天宮。

這個模擬系統的設計如下:

五、命令模式的實現

首先命令應當"重"一些還是"輕"一些。在不同的情況下,可以做不同的選擇。如果把命令設計得"輕",那麼它只是提供了一個請求者和接收者之間的耦合而己,命令代表請求者實現請求。

相反,如果把命令設計的"重",那麼它就應當實現所有的細節,包括請求所代表的操作,而不再需要接收者了。當一個系統沒有接收者時,就可以采用這種做法。

更常見的是處於最"輕"和最"重"的兩個極端之間時情況。命令類動態地決定調用哪一個接收者類。

其次是否支持undo和redo。如果一個命令類提供一個方法,比如叫unExecute(),以恢復其操作的效果,那麼命令類就可以支持undo和redo。具體命令類需要存儲狀態信息,包括:

1. 接收者對象實際上實施請求所代表的操作;

2. 對接收者對象所作的操作所需要的參數;

3. 接收者類的最初的狀態。接收者必須提供適當的方法,使命令類可以通過調用這個方法,以便接收者類恢復原有狀態。

如果只需要提供一層的undo和redo,那麼系統只需要存儲最後被執行的那個命令對象。如果需要支持多層的undo和redo,那麼系統就需要存儲曾經被執行過的命令的清單,清單能允許的最大的長度便是系統所支持的undo和redo的層數。沿著清單逆著執行清單上的命令的反命令(unExecute())便是undo;沿著清單順著執行清單上的命令便是redo。

六、命令模式的實際應用案例

下面的代碼使用命令模式演示了一個簡單的計算器,並允許執行undo與redo。注意:"Operator"在C#中是關鍵詞,所以在前面添加一個"@"將其變為標識符。

// Command pattern -- Real World example 
using System;
using System.Collections;
// "Command"
abstract class Command
{
 // Methods
 abstract public void Execute();
 abstract public void UnExecute();
}
// "ConcreteCommand"
class CalculatorCommand : Command
{
 // FIElds
 char @Operator;
 int Operand;
 Calculator calculator;
 // Constructor
 public CalculatorCommand( Calculator calculator,
  char @operator, int Operand )
 {
  this.calculator = calculator;
  this.@operator = @Operator;
  this.operand = Operand;
 }
 // PropertIEs
 public char Operator
 {
  set{ @Operator = value; }
 }
 public int Operand
 {
  set{ Operand = value; }
 }
 // Methods
 override public void Execute()
 {
  calculator.Operation( @operator, Operand );
 }
 
 override public void UnExecute()
 {
  calculator.Operation( Undo( @operator ), Operand );
 }
 // Private helper function
 private char Undo( char @Operator )
 {
  char undo = ' ';
  switch( @Operator )
  {
   case '+': undo = '-'; break;
   case '-': undo = '+'; break;
   case '*': undo = '/'; break;
   case '/': undo = '*'; break;
  }
  return undo;
 }
}
// "Receiver"
class Calculator
{
 // FIElds
 private int total = 0;
 // Methods
 public void Operation( char @operator, int Operand )
 {
  switch( @Operator )
  {
   case '+': total += Operand; break;
   case '-': total -= Operand; break;
   case '*': total *= Operand; break;
   case '/': total /= Operand; break;
  }
  Console.WriteLine( "Total = {0} (following {1} {2})",
   total, @operator, Operand );
 }
}
// "Invoker"
class User
{
 // FIElds
 private Calculator calculator = new Calculator();
 private ArrayList commands = new ArrayList();
 private int current = 0;
 // Methods
 public void Redo( int levels )
 {
  Console.WriteLine( "---- Redo {0} levels ", levels );
  // Perform redo Operations
  for( int i = 0; i < levels; i++ )
   if( current < commands.Count - 1 )
    ((Command)commands[ current++ ]).Execute();
 }
 public void Undo( int levels )
 {
  Console.WriteLine( "---- Undo {0} levels ", levels );
  // Perform undo Operations
  for( int i = 0; i < levels; i++ )
   if( current > 0 )
    ((Command)commands[ --current ]).UnExecute();
 }
 public void Compute( char @operator, int Operand )
 {
  // Create command Operation and execute it
  Command command = new CalculatorCommand(
   calculator, @operator, Operand );
  command.Execute();
  // Add command to undo list
  commands.Add( command );
  current++;
 }
}
/**//// <summary>
/// CommandApp test
/// </summary>
public class ClIEnt
{
 public static void Main( string[] args )
 {
  // Create user and let her compute
  User user = new User();
  user.Compute( '+', 100 );
  user.Compute( '-', 50 );
  user.Compute( '*', 10 );
  user.Compute( '/', 2 );
  // Undo and then redo some commands
  user.Undo( 4 );
  user.Redo( 3 );
 }
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved