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

設計模式之--命令模式

編輯:C#入門知識

 

命令模式的意圖一是將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化;二是對請求排隊或記錄請求日志,以及支持可撤消的操作。簡略圖如下:

\

 

 

命令模式通過對命令的封裝,將命令的請求(調用者Invoker)和執行(接收者Receiver)進行了責任分離,委派給不同的對象,不僅使得調用者和執行者之間實現了解耦(命令的請求方就不需要知道接收方的接口,也不需要知道命令是如何執行的具體情況),還使得可以記錄命令的執行記錄,添加執行日志,使得命令的控制、執行、取消和重做變得容易。

 

Delphi的Action就采用了這種模式,其中Windows控件(比如按鈕,菜單)是調用者,Action是命令,而接收者是Action的OnExecute事件的實現者。當然,Delphi為了實現設計期間或者運行期間控件的變灰,控件的Caption能在需要時與Action保持一致,在中間加了一個ActionLink類層次結構,采用的是橋模式,控件將控件與Action之間的通信交給ActionLink來完成,而AcionLink對象的創建則采用的是工廠方法(工廠就是控件本身),只不過它利用了GetActionLinkClass函數做得更加巧妙。而Action的具體執行采用事件的方式,又使得命令和接收者進一步解耦,這樣命令就不需要知道接收者的接口,也不用維護對接收者的引用,接收者也不需要知道命令的具體細節,只需要提供一個符合要求的事件處理方法即可。

 

下面是示例代碼:

 

/// <summary>

/// Command類,定義一個執行操作的接口,也可以是一個接口。

/// </summary>

public abstract class Command_Command

{

  protected Command_Receiver _Receiver;

  public abstract void Execute();

  public Command_Receiver Receiver

  {

   get

   {

    return _Receiver;

   }

   set

   {

    _Receiver = value;

   }

  }

}

public class Command_ConcreateCommand : Command_Command

    {

  public Command_ConcreateCommand()

  {

  }

  public override void Execute()

  {

   if(System.Windows.Forms.MessageBox.Show("你想執行操作麼?","系統提示!",

    System.Windows.Forms.MessageBoxButtons.YesNo)==System.Windows.Forms.DialogResult.Yes)

   {

    if(this._Receiver!=null)

    {

     this._Receiver.Action();

    }

   }

  }

 

    }

public class Command_Receiver

{

  public Command_Receiver()

  {

  }

  public void Action()

  {

   System.Windows.Forms.MessageBox.Show("Command Execute!");

  }

}

public class Command_Invoker

{

  private Command_Command command;

  public Command_Invoker()

  {

  }

  public void SetCommand(Command_Command command)

  {

   this.command = command;

  }

  public void Execute()

  {

   this.command.Execute();

  }

}

public class Command_Client

{

  public static void Test()

  {

   //建立具體命令

   Command_ConcreateCommand command = new Command_ConcreateCommand();

   //建立具體接收者

   Command_Receiver r1 = new Command_Receiver();

   //鏈接命令與接收者

   command.Receiver = r1;

            //創建調用者

   Command_Invoker invoker = new Command_Invoker();

   //設置調用者的命令子類

   invoker.SetCommand(command);

   //執行調用操作

   invoker.Execute();

  }

}

 

總結:

 

     如果沒有將命令的請求和執行進行責任分離並委托給不同的對象,那麼請求與執行都需要在同一個對象內完成,比如Button的Click命令,但這就帶來一個問題,Button的Click邏輯太復雜,因為同樣是Button,不同的用戶請求Click命令時執行的業務邏輯可能完全不同,而且通過Button的子類化來實現也根本不現實。所以,命令的請求和執行的責任必須分離為好,要實現分離有兩種辦法,一是采用回調函數(原來的Windows系統比較普遍),二是采用事件或委托(Delphi對象方法),三就是采用命令模式。1,2實際上屬於同一類型的處理方式,好處是簡單(後記:這種應用模式雖然比較普遍,但還有一個缺點就是頁面設計者和頁面邏輯實現很難分離,比如dotnet的aspx頁面和對應的.cs之間的耦合由於太緊密,很難實現UI設計和UI邏輯實現的分離,silverlight的VM就是為了彌補這個缺陷.)。但缺點是沒法對命令本身進行管理(執行,取消,日志,重做等)。如果命令本身不需要管理和控制,使用2比較好,現在的界面控件的命令處理基本都是采用這種方式進行。如果需要管理命令本身就要采用Command模式。

 

     如果對接收者進行抽象,就可以實現命令和接收者的動態組合,這有點類似裝飾模式,策略模式。

 

     對命令模式的一個改進就是可以將命令中接收者引用除掉,利用事件或者委托的辦法與接受者發生聯系。如果再對調用者進行抽象,這樣就形成了一個調用者體系和命令體系,如果需要兩者的聯系可再增加一個聯系層,這樣就有3個相對獨立的層次體系,Delphi的Action模式就是這樣的。這樣做有利於系統的可視化設計。

 

後記:命令模式在現在的編程體系中,使用非常廣泛,特別是在UI層與控制層或者業務邏輯層之間的解耦合方面作用非常大,當然,不好的地方是增加了系統的復雜度。silverlight編程中的mvvm模式中的vm層其實就可以看做是一個命令層,由這個層銜接M和V兩層,同時這個層與頁面層得銜接不再是傳統的頁面和.cs的關系,而是采用直接在UI中進行綁定的方式進行(傳統的方式是將頁面事件綁定到對應的後台.cs文件,這個文件在mvvm模式中也有,除了缺省的代碼和掛接VM的代碼外,已經沒什麼代碼,如果采用動態綁定V-VM,基本就只剩下缺省代碼了,因此UI設計完全不用考慮對這個文件的影響),這就使得頁面設計和頁面實現邏輯分離,可以很好的實現UI設計和UI邏輯開發的責任分割,從而實現設計更加專業化。副作用就是需要增加了很多類和接口。

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