【问题标题】:Decoupling command (pattern) sending classes from receivers?从接收者发送类的解耦命令(模式)?
【发布时间】:2012-08-03 00:56:13
【问题描述】:

因此,为了在任何类中创建命令(基于模式),该类必须知道接收者类,以便将其传递给命令的构造函数,然后将类耦合在一起。有没有办法使用命令模式并保持两个类之间的间接度量?

我能想到的唯一解决方案是:

  • 使用调解器,但我不知道具体如何,因为至少该命令仍需要传递给类,即使它只是它的接口
  • 使用外观,但这会将任何命令调用类耦合到外观
  • 使用事件系统而不是命令,但这在执行和编写代码本身时开销太大
  • 使用创建模式以某种方式创建命令,但将所有内容与该对象耦合

我对事件系统最大的担忧是,根据我在事件系统方面的经验,您必须编写大量代码才能让发送者和接收者在彼此不知情的情况下进行交互,这很疯狂而且根本不实用——我想要的每一种方法由事件访问需要我修改至少一个其他类,通常更多,这会产生与紧密耦合的 spegetti 代码一样糟糕的问题。另外我通常需要类来发送对事件的响应,这也很麻烦。

【问题讨论】:

    标签: c# design-patterns


    【解决方案1】:

    命令模式并不是为了解耦创建者和接收者;这些类通常已经耦合,甚至可能是同一个类。

    命令模式所做的是将实现与执行命令的类分离。一旦创建了命令,就可以将其传递给 UI 层或通过网络传递给远程客户端,并且执行类不需要任何关于如何实现命令的知识。

    【讨论】:

    • 在这种情况下,哪种创建模式适合与命令一起使用?是否会将创建对象放置在接收器上,然后可以通过通过命令创建者接口实现的属性访问?如果是这样的话,如果你想规范它与其他类的交互,那么让类只暴露命令创建接口是否有意义?
    • @Ford:这取决于您的用例。可能很难想出一个通用的创建界面,因为不同的命令可能需要不同的参数来创建。
    • 是的...我正在尝试使命令的子类依赖于与接收器相同的接口,而不是为每个新的命令创建新的子类方法,向接口添加方法会自动使它们对客户端可用...
    【解决方案2】:

    首先,不要使用外观。如果您从一开始就在设计中添加外观,您可能需要重新考虑您的设计。外观的主要目的是隐藏要简化交互的代码——通常是遗留代码。理想情况下,新代码应该从一开始就使用更简单的界面来设计。

    在不了解您的具体问题的情况下,我有一些建议:

    1. 继续使用事件系统。 C# 有一个很棒的事件系统,您可以利用它而无需编写太多自己的代码;只需定义一些委托并添加事件处理程序,您就大功告成了。发送事件的机制被抽象出来,因此您的大部分工作就是将它们连接在一起。如果您以前没有经常使用事件,那么一些快速搜索应该会为您提供大量有用的信息。

    2. 在执行时指定接收者:

      public interface ICommand {
          public void Execute(IReceiver receiver);
      }
      

      这允许接收器在调用Execute() 时动态更改,这使得这种模式的使用可以作为在系统中传递行为的一种方式。不过,在这一点上,有一种更好的方法可以达到同样的效果......

    3. 传递函数,而不是对象。 C# 再次发挥作用,允许函数像任何其他数据类型一样在系统中传递。将您的命令指定为委托:

      class MyThing {
          public delegate void Command(IReceiver receiver);
      
          public static void PrintReceiver(IReceiver receiver){
               // print the receiver
          }
      
          public static void ChangeReceiver(IReceiver receiver){
               // change something about the receiver
          }
      }
      

      稍后允许您执行以下操作:

      IReceiver receiver = someReceiverThatAlreadyExists;
      Command action = someCondition ? MyThing.PrintReceiver : MyThing.ChangeReceiver;
      action(receiver);
      

      这是一个过于简单化的示例,但说明了如何让行为类似于命令,但不需要完整的对象。

    【讨论】:

    • 代表很酷,但我不确定解决方案是否能解决我提到的问题...
    【解决方案3】:

    你可以拥有

    public interface ICommandHandler<T> where T : ICommand 
    {
        void Execute(T command);
    }
    

    当然,这需要一些路由代码来将您的命令从发布者传输到接收者。但是,如果您将此路由基于约定,那么编写一次的代码应该不会那么难。

    (我基于这样的想法,即 command 应该有一个单一的、定义明确的消费者。如果不是这种情况,那么这可能是一个事件,这有点不同,因为有兴趣的各方正在订阅事件本身)。

    【讨论】:

    • 听起来不错……命令子类可以包含定义接收器的接口成员,以便我想在接收器上公开的任何新方法自动变为可用。然后对于路由,我可以使用调解器或其他东西,这将查看同事是否具有与命令相同的接口,然后将其插入命令并执行它。这听起来是个好主意吗?
    • 如何定义命令接收者取决于您;取决于你想要多少去耦。你可以例如定义收件人类型,或者您可以只定义收件人名称并让中介为您找到它。
    猜你喜欢
    • 2016-05-18
    • 1970-01-01
    • 1970-01-01
    • 2015-06-03
    • 1970-01-01
    • 2015-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多