Hystrix


Il mondo è la totalità dei fatti non delle cose.
Archivio Posts
Anno 2018

Anno 2016

Anno 2015

Anno 2009

Anno 2008

Anno 2007

Anno 2006
Statistiche
  • Views Home Page: 65.924
  • Views Posts: 125.504
  • Views Gallerie: 0
  • n° Posts: 41
  • n° Commenti: 86

Hystrix.Broker e Tipi Generici

Da qualche tempo gioco con i tipi generici di c#, veramente belli e potenti.
Vorrei fare qui il riepilogo di una piccola dll denominata Hystrix.Broker.dll in cui li ho usati massicciamente e con gran soddisfazione.
Ecco il problema:

Scrivere un piccolo dispacciatore di messages in grado di inviare ai sottoscrittori di un certo topic un messaggio destinato a quel topic.

L'applicazioni è costituita da tre semplicissime classi:

- Un Engine : motore di tutta la faccenda
- Un Topic : rappresentante un thread e in grado di accoglie un ben determinato tipo di messaggi
- Un Message : classe astratta praticamente vuota da cui ereditare per creare Messages personalizzati.

Il concetto di Message ho cercato di tenerlo completamente generico, un Message è una roba qualunque che erediti dalla classe astratta e qui viene il primo problema. Quello che volevo era che il delegato da richiamare in caso di ricezione di un messaggio fosse ben tipizzato sul Message del caso, quindi ho docuto giocoforza usare un delegato generico, dichiarato come:

public delegate void MessageHandler<T>(T message) where T:Message;

Un Topic non è altro che una collezione di delagati che sottoscrivono quel Topic, anche il Topic è fortemente legato al Tipo di messagi a cui è associato ed è quindi pure lui un tipo generico. Per avere un Topic non generico da usare internamente Topic eredita da TopicBase, classe astratta vuota che implementa un solo metodo virtuale vuoto overridato dalla classe generica.

Topic espone solo metodi nascosti [internal], tipicamente:

- Subscribe, metodo generico sullo stesso tipo T della classe, si occupa di aggiungere alla lista [generica sul tipo T] il delegato passato
- Send, invoca ogni delegato sottoscrittore inviando il messaggio passato, topic ha quindi la semplice stuttura:

internal abstract class TopicBase
    {
        internal virtual void Send(Message m) { }
    }
    internal class Topic<T>:TopicBase where T:Message
    {
        private System.Collections.Generic.List<MessageHandler<T>> mHandlers=new System.Collections.Generic.List<MessageHandler<T>>();

        internal void Subscribe(MessageHandler<T> messageCallBack)
        {
            mHandlers.Add(messageCallBack);
        }
        internal override void Send(Message m)
        {
            if(!(m is T)) throw(new Common.Exceptions.InvalidTopic());
                
            foreach (MessageHandler<T> mh in mHandlers)
                mh.Invoke((T)m);
        }
    }


La classe Engine è pure semplicissima e generica in molteplici aspetti.
Si tratta di un singleton [Con una proprietà pubblica Current che si autoistanzia se necessario, del Broker quindi non va mai istanziato nulla :-D] in grado di raccogliere una collezione di Topics in un dizionario con chiave stringa [l'id del topic].
Espone un unico metodo generico:

- Subscribe, si occupa di creare se inesistente un determinatoi topic e di sottoscriverlo passando un delegato generico.

Contiene un inoltre un paio di metodi er la gestione del dizionario

public class Engine
    {
        private System.Collections.Generic.Dictionary<string,TopicBase> mTopics=new System.Collections.Generic.Dictionary<string,TopicBase>();
        private static Engine mCurrent;

        private Engine()
        {
        }
        public static Engine Current
        {
            get
            {
                if (mCurrent == null) mCurrent = new Engine();
                return mCurrent;
            }
        }
        public void Subscribe<T>(string topicKey, MessageHandler<T> messageCallBack) where T : Message
        {
            
            Topic<T> t = this.GetTopic<T>(topicKey, true);
            t.Subscribe(messageCallBack);
        }
        internal TopicBase GetTopic(string topicKey)
        {
            if (mTopics.ContainsKey(topicKey))
                return mTopics[topicKey];
            else
                return null;
        }
        internal Topic<T> GetTopic<T>(string topicKey, bool create) where T : Message
        {
            if (!mTopics.ContainsKey(topicKey))
            {
                if (create)
                {
                    Topic<T> t=new Topic<T>();
                    mTopics.Add(topicKey,t);
                    return t;
                }
                else 
                    return null;
            }
            return (Topic<T>)mTopics[topicKey];
        }
    }

La classe astratta Message a questo punto si limita a esporre un banalissimo metodo Send:

public abstract class Message
    {
        public void Send(string topicKey)
        {
            TopicBase t = Engine.Current.GetTopic(topicKey);
            if (t != null) t.Send(this);
        }
    }


Questa cinquantina di righe di codice mi sono costate un bel po' di riflessioni per far quadrare tutto, ma il risultato mi piace un sacco.
L'uso del mini-broker è ora straorinariamente semplice:

- E' possibile anzitutto creare un messaggio personalizzato, ad esempio:

public class TextMessage:Hystrix.Broker.Message
    {
        private string mText;
     
        public TextMessage(string text)
        {
            mText=text;
        }
        public string Text
        {
            get { return mText; }
        }
    }    

Fatto ciò una sottocrizione si limita a una cosa del tipo:

Hystrix.Broker.Engine.Current.Subscribe<TextMessage>(TopicKey, Handler);

E un invio di messaggi a una cosa del tipo:
new TextMessage("Ciao Mondo!").Send(TopicKey);

E' stato un bell'esercizio di stile divertente e intricato.
E funziona pure! :-D

Sto usando questa piccola dll per comunicare variazioni all'interno di un gestionale [Hystrix]. Quando viene ad esempio aggiunto uno scontrino, viene inviato un messaggio di aggiunta su un topic dedicato, sottoscritto da tutti gli oggetti che hanno a che fare con gli scontrini. A questo punto le griglie di scontrini si autoaggiornano, statistiche su scontrini visualizzano un messaggio del tipo 'Attenzione, i dati sono stati modificati e la statistica potrebbe non essere più aggiornata', altre finestre di edit si adeguano e così via. Combinato con una piccola gestione di rete l'aggiunta di un record può essere rilevata su tutte le istanze di Hystrix aperte in azienda e le potenzialità non sono finite, si può comunicare di tutto tanto che presto implementerò in Hystrix un piccolo messenger che permetta agli utenti del gestionale di comunicare in una piccola chat interna, il tutto basato sulle poche righe di codice qui sopra.

marc.


Categoria: C#
giovedì, 27 lug 2006 Ore. 13.22

Messaggi collegati


Calendario
dicembre 2024
lmmgvsd
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345
Ora e Data
Copyright © 2002-2007 - Blogs 2.0
dotNetHell.it | Home Page Blogs
ASP.NET 2.0 Windows 2003