运行FxCop在我的代码,我得到这个警告:

Microsoft。可维护性:'FooBar.构造函数与99 不同类型从9个不同的 命名空间。重写或重构 方法,以降低其级的联结, 或考虑移动的方法之一 其他类型它紧紧地 耦合。一类的联接上 40表示可怜的维护性, 类之间的联接40 30 指示中度可维护性, 和一个类的联接下面30 表示良好的维护性。

我的课上是一个降落区域的所有邮件服务器。服务器可以给我们消息的不同定引种类型:

public FooBar()
{
    var messageHandlers = new Dictionary<Type, Action<EventArgs>>();
    messageHandlers.Add(typeof(YouHaveBeenLoggedOutEventArgs), HandleSignOut);
    messageHandlers.Add(typeof(TestConnectionEventArgs), HandleConnectionTest);
    // ... etc for 90 other types
}

在"HandleSignOut"和"HandleConnectionTest"的方法有很少的代码;他们通常通过工作有了一个函数的另一类。

我怎么可以做这类更好地与下联接?

有帮助吗?

解决方案

让那些做工作的课程注册他们感兴趣的事件...... 事件经纪人模式。

class EventBroker {
   private Dictionary<Type, Action<EventArgs>> messageHandlers;

   void Register<T>(Action<EventArgs> subscriber) where T:EventArgs {
      // may have to combine delegates if more than 1 listener
      messageHandlers[typeof(T)] = subscriber; 
   }

   void Send<T>(T e) where T:EventArgs {
      var d = messageHandlers[typeof(T)];
      if (d != null) {
         d(e);
      }
   }
}

其他提示

你也可以使用某种海委会框架内,喜欢Spring.NET,注的字典。这种方式,如果得到一个新的信息类型,你不需要重新编译这个中心中心-只是改变配置文件。


期待已久的例子:

创建一个新的控制台应用程序、命名的例子,并添加这样的:

using System;
using System.Collections.Generic;
using Spring.Context.Support;

namespace Example
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            MessageBroker broker = (MessageBroker) ContextRegistry.GetContext()["messageBroker"];
            broker.Dispatch(null, new Type1EventArgs());
            broker.Dispatch(null, new Type2EventArgs());
            broker.Dispatch(null, new EventArgs());
        }
    }

    public class MessageBroker
    {
        private Dictionary<Type, object> handlers;

        public Dictionary<Type, object> Handlers
        {
            get { return handlers; }
            set { handlers = value; }
        }

        public void Dispatch<T>(object sender, T e) where T : EventArgs
        {
            object entry;
            if (Handlers.TryGetValue(e.GetType(), out entry))
            {
                MessageHandler<T> handler = entry as MessageHandler<T>;
                if (handler != null)
                {
                    handler.HandleMessage(sender, e);
                }
                else
                {
                    //I'd log an error here
                    Console.WriteLine("The handler defined for event type '" + e.GetType().Name + "' doesn't implement the correct interface!");
                }
            }
            else
            {
                //I'd log a warning here
                Console.WriteLine("No handler defined for event type: " + e.GetType().Name);
            }
        }
    }

    public interface MessageHandler<T> where T : EventArgs
    {
        void HandleMessage(object sender, T message);
    }

    public class Type1MessageHandler : MessageHandler<Type1EventArgs>
    {
        public void HandleMessage(object sender, Type1EventArgs args)
        {
            Console.WriteLine("Type 1, " + args.ToString());
        }
    }

    public class Type2MessageHandler : MessageHandler<Type2EventArgs>
    {
        public void HandleMessage(object sender, Type2EventArgs args)
        {
            Console.WriteLine("Type 2, " + args.ToString());
        }
    }

    public class Type1EventArgs : EventArgs {}

    public class Type2EventArgs : EventArgs {}
}

和一个应用程序。配置文件:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <sectionGroup name="spring">
      <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
      <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core"/>
    </sectionGroup>
  </configSections>

  <spring>
    <context>
      <resource uri="config://spring/objects"/>
    </context>
    <objects xmlns="http://www.springframework.net">

      <object id="messageBroker" type="Example.MessageBroker, Example">
        <property name="handlers">
          <dictionary key-type="System.Type" value-type="object">
            <entry key="Example.Type1EventArgs, Example" value-ref="type1Handler"/>
            <entry key="Example.Type2EventArgs, Example" value-ref="type2Handler"/>
          </dictionary>
        </property>
      </object>
      <object id="type1Handler" type="Example.Type1MessageHandler, Example"/>
      <object id="type2Handler" type="Example.Type2MessageHandler, Example"/>
    </objects>
  </spring>
</configuration>

输出:

Type 1, Example.Type1EventArgs
Type 2, Example.Type2EventArgs
No handler defined for event type: EventArgs

正如你可以看到, MessageBroker 不知道任何的处理程序,和处理程序不知道 MessageBroker.所有的映射是在应用程序。配置文件,以便如果需要处理的新事件的类型,可以添加在配置文件。这是特别好的如果其他队伍是决定性的事件类型和处理程序-他们可以只编译自己的东西在dll,你把它放到你的部署而简单地添加一映射。

该词典有价值的类型对象,而不是的 MessageHandler<> 因为实际的处理程序不能被赶到 MessageHandler<EventArgs>, 所以我不得不破解围绕这一点。我认为解决方案仍然是干净的,它处理的映射的错误。注意,你也会需要的参考Spring.Core.dll 在这个项目。你可以找到图书馆 在这里,, 和文件 在这里,.的 依赖注射章 被关到这一点。还注意到,没有任何理由需要使用Spring.NET 对于这一重要理念在这里是依赖注射。不知怎的,一些是需要告诉经纪人发送消息的类型,一个以x和使用IoC容器为依赖注射是一个很好的方式有经纪人不知道x,反之亦然。

其他一些这样的问题关系到海洋学委员会和二:

我没有看到你的其余代码,但我会尝试创建一个少得多的Event arg类。而是根据包含的数据和/或稍后处理它们的方式创建一些彼此相似的字段,并添加一个字段,告诉您发生的事件的确切类型(可能您应该使用枚举)。

理想情况下,您不仅可以使此构造函数更具可读性,还可以处理消息的方式(在单个事件处理程序中以类似方式处理的组消息)

也许不是为每条消息设置不同的类,而是使用标识消息的标志。

这将大大减少您拥有的邮件数量并提高可维护性。我的猜测是大多数消息类的差异都是零。

很难再选择一种攻击方式,因为架构的其余部分是未知的(对我而言)。

例如,如果你看一下Windows,它本身就不知道如何处理可能引发的每条消息。相反,底层消息处理程序向主线程注册回调函数。

您可能采取类似的方法。每个消息类都需要知道如何处理自己,并且可以使用更大的应用程序注册自己。这应该会大大简化代码并消除紧密耦合。

显然你需要一个调度机制:根据你收到的事件,你想要执行不同的代码。

您似乎正在使用类型系统来识别事件,而它实际上意味着支持多态。正如Chris Lively建议的那样,你也可以(不滥用类型系统)使用枚举来识别消息。

或者您可以拥抱类型系统的强大功能,并创建一个注册表对象,其中注册了每种类型的事件(通过静态实例,配置文件或任何其他方式)。然后,您可以使用“责任链”模式来查找正确的处理程序。处理程序自己处理它,或者它可能是Factory,创建一个处理事件的对象。

后一种方法看起来有点不明确和过度设计,但在99种事件类型(已经)的情况下,对我来说似乎是合适的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top