Rimani aggiornato sui commenti a questo articolo

molte volte capita di voler realizzare un programma nel quale un comportamento è in comune a tanti oggetti, ma che ad esempio può essere fatto in modi diversi. il primo esempio che mi viene in mente è la creazione di un logger, ovvero di un componente che gestisca in maniera autonoma il log del nostro programma: il modo in cui questo avviene a noi che facciamo il programma non interessa, ma a chi andrà poi a leggerlo sarà di primaria importanza che questo file abbia un senso logico e contenga tutte le informazioni necessarie per un buon debug. ecco perchè si è deciso di adottare il pattern singleton.

creiamo perciò un’interfaccia con tutte le funzioni che deve avere un buon logger:

public interface ILogger
{
void BeginLog(string filename);
void Log(string message);
void EndLog();
}

naturalmente la funzione Log può essere suddivisa in LogErrore, LogSemplice, LogWarning ecc ecc in base alle vostre esigenze. Io di solito uso un unica funzione di Log alla quale passo un oggetto LogMessage che contiene il tipo di messaggio, ma queste sono scelte progettuali indipendenti.

adesso creiamo la classe che andrà ad estendere l’interfaccia:

public class GenericLogger : ILogger
{
#region ILogger Members
public void BeginLog(string filename)
{
//non fa nulla
}
public void Log(string message)
{
//non fa nulla
}
public void EndLog()
{
//non fa nulla
}
#endregion
}

perchè è importante che tutte le funzioni non facciano nulla? semplice. Essendo che noi vogliamo fare dei plug-in, vogliamo che sia data la possibilità di usare il logger preferito. Ma mettiamo che per una determinata applicazione non vogliamo che venga creato il log, oppure che per un fortuito caso vengano cancellate le dll dei logger, chi si occuperà di questo? semplice, chi andrà a controllare l’esistenza dei plug-in, nel caso non trovi il logger scelto dall’utente andrà a prendere quello di default, in questo caso un logger che non fa nulla.

andiamo perciò ora a creare il singleton che restituirà un logger in base alla disponibilità:

public class Logger
{
private static Dictionary _instances = new Dictionary();
private static void Initialize()
{
foreach (FileInfo file in new DirectoryInfo(Application.StartupPath).GetFiles())
{
if (file.Extension == ".dll")
{
foreach (Type type in Assembly.LoadFile(file.FullName).GetTypes())
{
if (type.GetInterface("ILogger") != null)
_instances.Add (type.Name, (ILogger)Activator.CreateInstance(type));
}
}
}
if(!_instances.ContainsKey("GenericLogger"))
_instances.Add("GenericLogger", new GenericLogger());
}
}

questo codice controlla in ogni file presente nella cartella dell’eseguibile, se questo file è una dll allora controlla ogni oggetto al suo interno e se trova un oggetto che estende l’interfaccia ILogger allora ne crea un’istanza e la aggiunge al dizionario. al termine aggiunge un’istanza del logger generico di cui abbiamo detto poco fa.

se vogliamo fare vedere la lista dei logger allora dobbiamo creare un metodo che ce li elenchi, quindi:

public static List<string> Loggers(){
List</string><string> loggers = new List</string><string>();
foreach (ILogger logger in _instances.Values)
{
loggers.Add(logger.GetType().Name);
}
return loggers;
}

ecco quindi che ora abbiamo realizzato una base per il logger, ci manca solo da realizzare un logger che estenda l’interfaccia ILogger, creare la dll e metterla nella cartella del nostro programma e questo verrà “magicamente” visualizzato nella nostra lista smile emoticon

Sentiti libero/a di lasciare un commento a questo articolo, mi fa piacere se mi scrivi!
Se vuoi avere anche tu un'immagine personalizzata, iscriviti subito a gravatar! È gratis!