【问题标题】:How can I avoid violation of Open Closed with method parameters?如何避免使用方法参数违反 Open Closed?
【发布时间】:2014-05-22 13:01:52
【问题描述】:

在下面的代码中,MessageProcessor 类违反了 Open Closed 原则 - 每个新的 IMessage 实现都需要对此类进行更改。对于这种不违反 O/C 的场景,是否有一个很好的干净模式?

public interface IMessage
{
}

public class BlahMessage : IMessage
{
}

public class MoohMessage : IMessage
{
}

public class MessageStream
{
    public void Dispatch(IMessage message)
    {
        var messageProcessor = new MessageProcessor();
        messageProcessor.Handle(message);
    }
}

public class MessageProcessor
{
    public void Handle(IMessage message)
    {
        if (message is MoohMessage)
            Handle((MoohMessage)message);

        if (message is BlahMessage)
            Handle((BlahMessage)message);
    }

    private void Handle(MoohMessage moo)
    {
    }

    private void Handle(BlahMessage blah)
    {
    }
}

【问题讨论】:

  • 除了签名,Handle(MoohMessage moo)Handle(BlahMessage blah) 有什么不同?这些应该在单独的类中(可能是通用的)吗?
  • 为什么Handle 方法需要不同?乍一看,逻辑应该在消息本身上,MessageProcessor 应该只调用IMessage 上的通用方法来调用它。
  • 为什么不将 Process() 方法添加到 IMessage 并调用 message.Process() 而不是 messageProcessor.Handle(message)
  • @MVarman,让您的评论成为答案。这是答案。
  • 消息只是愚蠢的 DTO,它们毕竟是消息,它们本身不会有 Process() 方法。

标签: c# design-patterns language-agnostic open-closed-principle


【解决方案1】:

这里的问题是,MessageProcessor 类试图实现不同 Message 类的行为。

相反,您可以将 Process() 方法添加到 IMessage 并在每个 Message 类中实现它。

所以界面看起来像,

public interface IMessage
{
   Process();
}

而且,Dispatch 方法可以直接调用该方法

public void Dispatch(IMessage message)
{
  message.Process();
}

【讨论】:

  • 但这违反了 SRP,可以说更糟。消息就是这样 - 消息。它们不包含处理自身所需的逻辑,这甚至没有意义。
  • 我没有意识到 Message 对象是普通的 DTO。如果是这种情况,另一个选项是创建 IMessageProcessor 并实现 IBlahMessageProcessor 和 IMoohMessageProcessor。然后,您可以将 IMessageProcessor 对象注入 Dispatch() 方法或使用工厂模式创建处理器对象(如果您不介意factory class violating OCP)。
  • 抱歉,我应该更清楚一点.. 是的,我想在某些时候,除非您使用 DI 容器来自动连接您将违反 SRP 的处理程序...谢谢 :)
【解决方案2】:

您当前的MessageProcessor 不是因为处理多种消息而违反了 SRP 吗?

这里有一个可供考虑的选项:

  • 更改 MessageStream 以将消息发送到 Dispatcher。
  • 创建不同的消息处理类。
  • 在运行时向 Dispatcher 注册每个消息处理器。
  • Dispatcher 会将消息路由到正确的处理器。

当然,这种方法可能只是将 OCP 问题转移到另一个地方,在该地方创建 MessageProcessor 实例并使用 Dispatcher 重新注册。但至少它会清理许多if (message is XXX) 调用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多