2011-09-08 58 views
5

命令對象模式是我仍然無法真正掌握的,並且我在當前正在處理的代碼中發現了一個實現,所以我研究了它很久,很難看出我是否可以最終得到它真實世界的例子。問題是,我確信這個問題沒有得到很好的實施,而這只是一個剛剛閱讀過它並認爲它在這裏有意義的人的嘗試。命令對象模式wannabe還是真實的東西?

讓我拿出來給你(出於保密原因,將大大簡化,但我會盡我所能展示的主要概念):

public class CommandOne 
{ 
    public CommandOne(Manager manager, MyForm form) 
    { 
     m_manager = manager; 
     m_form = form; 
    } 

    public void Execute() 
    { 
     m_manager.CommandOne(m_form); 
    } 
} 

public class CommandTwo 
{ 
    public CommandTwo(Manager manager, MyForm form) 
    { 
     m_manager = manager; 
     m_form = form; 
    } 

    public void Execute() 
    { 
     m_manager.CommandTwo(m_form); 
    } 
} 

這令我奇怪的第一件事是這兩個類不是從任何抽象類繼承,也不是實現一個通用接口。

使用這些命令的代碼如下:

public class MyForm : System.Windows.Forms.Form 
{ 
    public MyForm(Manager manager) 
    { 
     m_manager = manager; 
    } 

    private void SomeMethod() 
    { 
     .... 
     var cmd = new CommandOne(manager, this); 
     cmd.Execute(); 
     ... 
    } 

    private void OtherMethod() 
    { 
     .... 
     var cmd = new CommandTwo(manager, this); 
     cmd.Execute(); 
     ... 
    } 
} 

所以我看到它的方式,這種形式是絕對連接到所有參與,除了其正在通過它的構造函數注入給它的經理類。所以對於這段代碼,我真的沒有看到創建「命令」類的好處,它基本上只是將調用委託給管理器的方法,因爲表單在需要它們時實例化它們,並在之後調用execute方法。

那麼,有人可以解釋一下,如果有這個實現缺少真正的命令對象模式,儘管它可能過於主觀,那麼在這種情況下實現它會有什麼好處?

謝謝。

+0

使用「Form」的命令是什麼? – SwDevMan81

+0

它被髮送到管理器中的委託方法,該管理器顯示消息框,詢問用戶他是否想保存或不更改其相應的修改表單的屬性。海事組織這是非常糟糕的設計,但我認爲,超出了問題的範圍:) –

回答

9

根據您在此處顯示的內容,看起來命令模式的優點會丟失。有幾個原因可能需要在WinForms應用程序的上下文中使用命令模式。

要執行的命令後

public interface ICommand 
{ 
    void Execute(); 
} 

保持執行的命令的歷史記錄,因此它們可以被用戶撤消

public interface ICommand 
{ 
    void Execute(); 

    void Undo(); 
} 

查看權限,查看當前用戶有權執行該命令。例如,也許你有RefundCustomerCommand,並不是所有的客戶服務代理都有權發放退款,所以你想禁用表單上的按鈕。

public interface ICommand 
{ 
    void Execute(); 

    bool CanExecute { get; } 
} 

也可以在這樣的複合軋輥的多個命令一起:

public class CompositeCommand : ICommand 
{ 
    private readonly List<ICommand> commands; 

    public CompositeCommand() 
    { 
     commands = new List<ICommand>(); 
    } 

    public void Add(ICommand command) 
    { 
     commands.Add(command); 
    } 

    public void Execute() 
    { 
     foreach (var command in commands) command.Execute(); 
    } 
} 

該命令模式也與裝飾很好地工作。您可以輕鬆地爲您的命令添加額外的交叉行爲,如重試邏輯:

public class RetryOnTimeout : ICommand 
{ 
    private readonly ICommand command; 
    private int numberOfRetries; 

    public RetryOnTimeout(ICommand command, int numberOfRetries) 
    { 
     this.command = command; 
     this.numberOfRetries = numberOfRetries; 
    } 

    public void Execute() 
    { 
     try 
     { 
      command.Execute(); 
     } 
     catch (TimeoutException) 
     { 
      if (++numberOfRetries > 3) 
       throw; 

      Execute(); 
     } 
    } 
} 
+0

謝謝邁克爾。所以從你的回答來看,如果表單仍然會實例化管理器(讓我們忘記關於管理器的依賴注入),那麼注入它自己,在某種組合中創建所有必要的命令,然後根據操作所需要的組合找到適當的命令返回其接口,以便表單可以運行其執行方法?還有第二個問題,雖然它可能是主觀的,這一切是有意義的,還是它是矯枉過正?使用另一種模式會更好嗎? –

+0

我並不真正關注你的情況。如果你的解決方案很複雜,希望這是因爲問題很複雜。儘管找到合適的命令並返回接口的想法很常見。例如,實現像SMTP這樣的協議的常見解決方案是擁有一個對象,該對象管理套接字,然後根據消息(HeloCommand,MailFromCommand,RcptToCommand等)分派到命令對象。命令對象可以動態查找。 –