Vous pouvez également utiliser une sorte de cadre IoC, comme Spring.NET, pour injecter le dictionnaire. De cette façon, si vous obtenez un nouveau type de message, vous n'avez pas besoin de recompiler ce concentrateur central - il suffit de changer un fichier de configuration.
L'exemple tant attendu:
Créer une nouvelle application de la console, nommée exemple, et ajoutez ceci:
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 {}
}
Et un fichier 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>
Sortie:
Type 1, Example.Type1EventArgs
Type 2, Example.Type2EventArgs
No handler defined for event type: EventArgs
Comme vous pouvez le voir, MessageBroker
ne connaît pas l'un des gestionnaires, et les gestionnaires ne connaissent pas MessageBroker
. Tout le mappage est fait dans l'application.fichier de configuration, de sorte que si vous devez gérer un nouveau type d'événement, vous pouvez l'ajouter dans le fichier de configuration. Cela est particulièrement agréable si d'autres équipes définissent des types d'événements et des gestionnaires - ils peuvent simplement compiler leur contenu dans une DLL, vous le déposez dans votre déploiement et vous ajoutez simplement un mappage.
Le dictionnaire a des valeurs de type objet au lieu de MessageHandler<>
parce que les gestionnaires réels ne peuvent pas être jeté à MessageHandler<EventArgs>
, donc je devais pirater autour un peu. Je pense que la solution est toujours propre et qu'elle gère bien les erreurs de mappage. Notez que vous devrez également référencer Spring.Core.dll dans ce projet. Vous pouvez trouver les bibliothèques here et la documentation here. Le est pertinent pour cela. Notez également qu'il n'y a aucune raison d'utiliser Spring.NET pour cela - l'idée importante ici est l'injection de dépendance. D'une manière ou d'une autre, quelque chose va devoir dire au courtier d'envoyer des messages de type a à x, et l'utilisation d'un conteneur IoC pour l'injection de dépendances est un bon moyen pour que le courtier ne sache pas x, et vice versa.
Une autre SO question relative à IoC et DI:
J'aime les réponses ici, mais peut-être un endroit comme RefactorMyCode.com pourrait être un meilleur endroit pour cela. Il est un peu plus facile pour tout le monde d'afficher du code dans leurs réponses sur ce site. –
Ok, j'ai posté l'exemple, vérifiez-le –