設計モード:コマンドモード(Command Pattern)

15471 ワード

作者:TerryLee創建于:2006-07-17出典:http://terrylee.cnblogs.com/archive/2006/07/17/Command_Pattern.html収録于:2013-02-28
概要
ソフトウェアシステムでは、動作要求者と動作実装者は、通常、「緊密な結合」を示す.しかし、場合によっては、動作を「記録、取り消し/やり直し、トランザクション」などの処理を行うなど、変化を防ぐことができない緊密な結合は適切ではありません.この場合、「動作リクエスト者」と「動作実装者」をどのようにデカップリングしますか?一組の行為を対象として抽象化し,両者の間の松結合[李建忠]を実現できる.これが本稿で言うCommandモードです.
構造図
设计模式:命令模式(Command Pattern)
意図
1つのリクエストをオブジェクトにカプセル化し、異なるリクエストで顧客をパラメータ化できます.リクエストに対してキューまたはログを記録し、取り消し可能な操作をサポートします.
適用性
  • は、オブジェクト指向システムにおける「CallBack」の代替としてコマンドモードを使用する.「CallBack」は、まず1つの関数を登録し、後でこの関数を呼び出すことを意味します.
  • は、異なる時間にリクエストを指定し、リクエストをキューに入れる必要がある.1つのコマンドオブジェクトと元のリクエスト発行者は、異なるライフサイクルを持つことができます.すなわち、元のリクエスト送信者はもういないかもしれないが、コマンドオブジェクト自体はまだアクティブである.この場合、コマンドの受信者は、ローカルであってもよいし、ネットワークの別のアドレスであってもよい.コマンドオブジェクトは、シリアル化後に別のマシンに転送できます.
  • システムは、コマンドの取り消しをサポートする必要がある.コマンドオブジェクトは、クライアントがコマンドによる効果を取り消す必要がある場合にundo()メソッドを呼び出し、コマンドによる効果を取り消すことができます.コマンドオブジェクトは、クライアントが必要に応じてコマンド効果を再実施するためのredo()メソッドも提供することができる.
  • システムがシステムのすべてのデータをログに更新する場合、システムがクラッシュしたときに、ログに基づいてすべてのデータ更新コマンドを読み返し、Execute()メソッドを1つずつ呼び出してこれらのコマンドを実行し、システムがクラッシュする前に行ったデータ更新を復元することができます.

  • インプリメンテーションコード
     
    设计模式:命令模式(Command Pattern)


    View Code
     1 public class Document
    
     2 {
    
     3     //     
    
     4     public void Display()
    
     5     {
    
     6         Console.WriteLine("Display");
    
     7     }
    
     8     //     
    
     9     public void Undo()
    
    10     {
    
    11         Console.WriteLine("Undo");
    
    12     }
    
    13     //     
    
    14     public void Redo()
    
    15     {
    
    16         Console.WriteLine("Redo");
    
    17     }
    
    18 }
    
    19 public abstract class DocumentCommand
    
    20 {
    
    21     Document _document;
    
    22     public DocumentCommand(Document doc)
    
    23     {
    
    24         this._document = doc;
    
    25     }
    
    26     public abstract void Execute();
    
    27 }
    
    28 //     
    
    29 public class DisplayCommand : DocumentCommand
    
    30 {
    
    31     public DisplayCommand(Document doc) : base(doc)
    
    32     { }
    
    33     public override void Execute()
    
    34     {
    
    35         _document.Display();
    
    36     }
    
    37 }
    
    38 //     
    
    39 public class UndoCommand : DocumentCommand
    
    40 {
    
    41     public UndoCommand(Document doc) : base(doc)
    
    42     { }
    
    43     public override void Execute()
    
    44     {
    
    45         _document.Undo();
    
    46     }
    
    47 }
    
    48 //     
    
    49 public class RedoCommand : DocumentCommand
    
    50 {
    
    51     public RedoCommand(Document doc) : base(doc)
    
    52     { }
    
    53     public override void Execute()
    
    54     {
    
    55         _document.Redo();
    
    56     }
    
    57 }
    
    58 // Invoker  
    
    59 public class DocumentInvoker
    
    60 {
    
    61     DocumentCommand _discmd;
    
    62     DocumentCommand _undcmd;
    
    63     DocumentCommand _redcmd;
    
    64     public DocumentInvoker(DocumentCommand discmd, DocumentCommand undcmd, DocumentCommand redcmd)
    
    65     {
    
    66         this._discmd = discmd;
    
    67         this._undcmd = undcmd;
    
    68         this._redcmd = redcmd;
    
    69     }
    
    70     public void Display()
    
    71     {
    
    72         _discmd.Execute();
    
    73     }
    
    74     public void Undo()
    
    75     {
    
    76         _undcmd.Execute();
    
    77     }
    
    78     public void Redo()
    
    79     {
    
    80         _redcmd.Execute();
    
    81     }
    
    82 }
    
    83 class Program
    
    84 {
    
    85     static void Main(string[] args)
    
    86     {
    
    87         Document doc = new Document();
    
    88         DocumentCommand discmd = new DisplayCommand(doc);
    
    89         DocumentCommand undcmd = new UndoCommand(doc);
    
    90         DocumentCommand redcmd = new RedoCommand(doc);
    
    91         DocumentInvoker invoker = new DocumentInvoker(discmd, undcmd, redcmd);
    
    92         invoker.Display();
    
    93         invoker.Undo();
    
    94         invoker.Redo();
    
    95     }
    
    96 }

    1.クライアントプログラムでは、DocumentのDisplay()、Undo()、Redo()コマンドに依存せず、これらのコマンドをCommandでカプセル化し、その1つの鍵は抽象的なCommandクラスであり、操作のインタフェースを定義している.また,本来この3つの命令は3つの方法にすぎないが,Commandモードによってそれらをクラスレベルに言及することは,実際にはオブジェクト向けの原則に反しているが,命令を分離する要求者と命令の実行者の問題を優雅に解決し,Commandモードを使用する際には,その使用タイミングを判断しなければならない.
    2.上記のUndo/Redoは単純に概略的に実現されているだけで、このような効果を実現するには、コマンドオブジェクトに状態を設定する必要があり、コマンドオブジェクトによって状態を格納することができる.
    効果と実現のポイント
    1.Commandモードの根本的な目的は、「動作要求者」と「動作実装者」をデカップリングすることであり、オブジェクト向け言語では、一般的な実装手段は「動作をオブジェクトとして抽象化する」ことである.
    2.Commandインタフェースを実装する特定のコマンドオブジェクトConcreteCommandは、必要に応じて追加のステータス情報を保存する場合があります.
    3.Compmositeモードを使用することで、複数のコマンドを1つの「複合コマンド」MacroCommandにカプセル化できます.
    4.CommandモードはC#のDelegateと似ています.しかし、両者の定義行為インタフェースの規範には違いがある:Commandはオブジェクト向けの「インタフェース-実装」で行為インタフェースの規範を定義し、より厳格で、抽象的な原則に合致する.Delegateは関数署名で動作インタフェース仕様を定義し,より柔軟であるが抽象能力は弱い.
    5.コマンド・モードを使用すると、特定のコマンド・クラスが多すぎるシステムがあります.いくつかのシステムでは、数十個、数百個、数千個の具体的なコマンドクラスが必要になる可能性があります.これにより、コマンドモードはこのようなシステムでは現実的ではありません.
    まとめ
    Commandモードは非常に簡単で優雅な設計モードであり、その根本的な目的は「動作要求者」と「動作実現者」をデカップリングすることである.