設計模式筆記(15)—命令模式(行為型)

來源:互聯網
上載者:User
文章目錄
  • Gof定義
  • 動機
  • Command模式的幾個要點
Gof定義

將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支援可撤銷的操作。

動機

在軟體構建過程中,“行為要求者”與“行為實現者”通常呈現一種“緊耦合”。但在某些場合——比如需
要對行為進行“記錄、撤銷/重做(undo/redo)、事務”等處理,這種無法抵禦變化的緊耦合是不合適的。在這種情況下,如何將“行為要求者”與“行為實現者”解耦?將一組行為抽象為對象,可以實現二者之間的松耦合。

先來看個反例(版本1),假設在一個應用程式中需要用到要用到很多的一些外部的類,並且要對這些類中的操作進行撤銷、記錄等操作,如果像下面這樣實現就會很亂並且不容易實現:

public class Application{    public void Process()    {        Document doc = new Document();        doc.ShowText();        Graphics gra = new Graphics();        gra.Draw();        //需要進行undo 記錄等操作    }}public class Document{    public void ShowText() { }}public class Graphics{    public void Draw(){ }}

 

要滿足上面提的那些要求就需要用命令模式,命令模式結構圖如下:

改進後的代碼(版本2),將ShowText Draw這種行為抽象起來放到一個介面中,介面命名為ICommand,並且在該介面中還有一個方法簽名Undo,用來做撤銷處理,當然根據需要還可以加其他的操作。ICommand代碼如下:

public interface ICommand{    void Execute();    void Undo();}

Document類和Graphics類實現該介面,並提供自己的實現,代碼如下:

public class Document:ICommand{    public string Name { get;set;}    public Document(string name)    {        Name = name;    }    public void Execute()    {        Console.WriteLine("顯示文本 "+Name);    }    public void Undo()    {        Console.WriteLine("撤銷顯示文本 "+Name);    }}public class Graphics : ICommand{    public string Name { get;set;}    public Graphics(string name)    {        Name = name;    }    public void Execute()    {        Console.WriteLine("畫圖 "+Name);    }    public void Undo()    {        Console.WriteLine("撤銷畫圖 "+Name);    }}

用戶端調用的代碼:

public class Application{    public Stack<ICommand> stack=new Stack<ICommand>();    public void Show()    {        foreach (ICommand cmd in stack)        {            cmd.Execute();        }    }    public void Undo()    {        ICommand command = stack.Pop();        command.Undo();    }}
static void Main(string[] args){    Application app = new Application();    app.stack.Push(new Document("1"));    app.stack.Push(new Graphics("1"));    app.stack.Push(new Document("2"));    app.stack.Push(new Graphics("2"));        app.Show();    app.Undo();    Console.ReadLine();}

上面的代碼運行結果如下:

從結果中可以看出,最後執行的畫圖2 被撤銷了。

在上面的代碼中,像Document、Graphics這樣的類都是實現了ICommand介面,如果項目中已經存在這樣的類然後還要將這些類去實現ICommand介面,顯然不是很合理,那麼就需要添加DocumentCommand類來進行轉化。完整代碼如下(版本3):

public class Document{    public void ShowText()    {        Console.WriteLine("顯示文本 ");    }}public class Graphics{    public void Draw()    {        Console.WriteLine("畫圖 ");    }}public interface ICommand{    void Execute();    void Undo();}/// <summary>/// 具體化的文檔命令類/// </summary>public class DocumentCommand : ICommand{    Document _doc;    public DocumentCommand(Document doc)    {        _doc = doc;    }    public void Execute()    {        _doc.ShowText();    }    public void Undo()    {        Console.WriteLine("撤銷顯示文本 ");    }}/// <summary>/// 具體化的映像命令類/// </summary>public class GraphicsCommand : ICommand{    Graphics _gra;    public GraphicsCommand(Graphics gra)    {        _gra = gra;    }    public void Execute()    {        _gra.Draw();    }    public void Undo()    {        Console.WriteLine("撤銷畫圖 ");    }}public class Application{    public Stack<ICommand> stack = new Stack<ICommand>();    public void Show()    {        foreach (ICommand cmd in stack)        {            cmd.Execute();        }    }    public void Undo()    {        ICommand command = stack.Pop();        command.Undo();    }}class Program{    static void Main(string[] args)    {        Application app = new Application();        app.stack.Push(new DocumentCommand(new Document()));        app.stack.Push(new GraphicsCommand(new Graphics()));        app.Show();        app.Undo();        Console.ReadLine();    }}

在版本1中Application類中直接和Document中的方法相耦合,進過一步步改進後,Application類只和Document和Graphics的抽象耦合,達到瞭解耦的目的。

Command模式的幾個要點
  • Command模式的根本目的在於將“行為要求者”與“行為實現者” 解耦,在物件導向語言中,常見的實現手段是“將行為抽象為對象”。
  • 實現Command介面的具體命令對象ConcreteCommand有時候根據需要可能會儲存一些額外的狀態資訊。
  • 通過使用Composite模式,可以將多個“命令”封裝為一個“複合命令”MacroCommand。
  • Command模式與C#中的Delegate有些類似。但兩者定義行為介面的規範有所區別:Command以物件導向中的“介面-實現”來定義行為介面規範,更嚴格,更符合抽象原則;Delegate以函數簽名來定義行為介面規範,更靈活,但抽象能力比較弱。

返回開篇(索引)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.