使用C#Action委托实现命令模式

Dve*_*Dve 7 c# delegates design-patterns command-pattern

是否可以使用Queue of Action代理实现GOF命令模式?

我一直试图绕过它一段时间而且我很难过,因为我想要添加到队列中的每个可能的动作可能有不同数量的参数.

有什么建议?我是否通过专注于命令模式来咆哮错误的树?

更新:

非常感谢jgauffin,这是一种享受...我的实现现在看起来像

public class CommandDispatcher
{
    private readonly Dictionary<Type, List<Action<ICommand>>> _registeredCommands =
        new Dictionary<Type, List<Action<ICommand>>>();

    public void RegisterCommand<T>(Action<ICommand> action) where T : ICommand
    {
        if (_registeredCommands.ContainsKey(typeof (T)))
            _registeredCommands[typeof (T)].Add(action);
        else
            _registeredCommands.Add(typeof (T), new List<Action<ICommand>> {action});
    }

    public void Trigger<T>(T command) where T : ICommand
    {
        if (!_registeredCommands.ContainsKey(typeof(T)))
            throw new InvalidOperationException("There are no subscribers for that command");

        foreach (var registeredCommand in _registeredCommands[typeof(T)])
        {
            registeredCommand(command);
            if (command.Cancel) break;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

jga*_*fin 10

您可以使用Action.您不应该使用多个参数.如果命令需要新参数会发生什么?然后,您需要更改调用该命令的所有位置以及处理程序.

相反,您应该使用具有所有参数作为属性的Command类.通过这种方式,您可以添加参数而不会影响代码(新参数应在处理程序中视为可选参数).

我就是这样做的:

public interface ICommand
{
    // Cancel processing, do not invoke any more handlers
    public bool Cancel { get; set; }
}

public class CommandDispatcher 
{
  private Dictionary<Type, List<Action<ICommand>>> _commands = new Dictionary<Type, List<Action<ICommand>>>();


  // Add to dictionary here
  public void Subscribe<T>(Action<T> action) where T : ICommand
  {
      List<Action<ICommand>> subscribers;
      if (!_commands.TryGetValue(typeof(T), out subscribers))
      {
          subscribers = new List<Action<ICommand>>();
          _commands.Add(typeof(T), subscribers));
      }

      subscribers.Add(action);
  }

  // find command and to foreach to execute the actions      
  public void Trigger<T>(T command) where T : ICommand
  {
      List<Action<ICommand>> subscribers;
      if (!_commands.TryGetValue(typeof(T), out subscribers))
          throw new InvalidOperationException("There are no subscribers for that command");

      foreach(var subsriber in subscribers)
      {
          subscriber(command);
          if (command.Cancel)
              break; //a handler canceled the command to prevent others from processing it.
      }
  }

}

public class AddTextCommand : ICommand
{
    public string TextToAdd {get;set;}
}

public class TextHandler
{
    public TextHandler(CommandDispatcher dispatcher)
    {
        disptacher.Subscribe<AddTextCommand>(OnAddText);
    }

    public void OnAddText(AddTextCommand cmd)
    {
        //....
    }
}


public partial class MyForm : Form
{
    CommandDispatcher _dispatcher;

    private void MyTextBox_Changed(object source, EventArgs e)
    {
        _dispatcher.Trigger(new AddTextCommand{TextToAdd = MyTextBox.Text}=;
    } 
}
Run Code Online (Sandbox Code Playgroud)

请注意,代码是一种伪代码.我在没有测试的情况下直接在答案中写了它.您可能需要更改内容以使其正常工作,但它至少应该给您一个提示.实现允许您为每个命令添加多个订户.