Вы также можете использовать своего рода IoC-инфраструктуру, например Spring.NET, для добавления словаря. Таким образом, если вы получаете новый тип сообщения, вам не нужно перекомпилировать этот центральный хаб - просто измените файл конфигурации.
<Ч />
Долгожданный пример:
Создайте новое консольное приложение с именем Example и добавьте следующее:
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 {}
}
И файл app.config:
<?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
. Все сопоставление выполняется в файле app.config, поэтому, если вам нужно обработать новый тип события, вы можете добавить его в файл конфигурации. Это особенно хорошо, если другие команды определяют типы событий и обработчики - они могут просто скомпилировать свои вещи в dll, добавить их в свое развертывание и просто добавить отображение.
В словаре есть значения типа object вместо MessageHandler<>
, потому что фактические обработчики не могут быть преобразованы в MessageHandler<EventArgs>
, поэтому мне пришлось немного поработать над этим. Я думаю, что решение все еще чистое, и оно хорошо обрабатывает ошибки отображения. Обратите внимание, что вам также нужно будет ссылаться на Spring.Core.dll в этом проекте. Вы можете найти библиотеки здесь и документацию здесь . глава внедрения зависимостей имеет отношение к этому. Также обратите внимание, что для этого не нужно использовать Spring.NET - важная идея здесь - внедрение зависимостей. Каким-то образом нужно что-то сказать брокеру отправлять сообщения типа a в x, и использование контейнера IoC для внедрения зависимостей - хороший способ не дать брокеру не знать о x, и наоборот.
Некоторые другие вопросы SO, связанные с IoC и DI: