Funzionalità estendibile per opzioni collegabili in C #

6

Ero interessato a come dovrebbe essere affrontato il seguente approccio sia pragmatico che orientato al modello. Preferirei una risposta di mondo reale su "modello corretto".

Esempio semplice: Supponiamo che io voglia un sistema di registrazione degli eventi in cui gli sviluppatori chiamino semplicemente il metodo di registro e forniscano un tag personalizzato solo per stampare come prefisso all'errore.

IEventLog eventLog = new StandardEventLog();
eventLog.LogData("trace data", new TraceLogType());
eventLog.LogData("error data", new ErrorLogType());

dove quanto sopra è definito come tale.

public interface IEventLog
{
    string Log { get; set; }
    void LogData(string log, EventLogType type);
}

public class StandardEventLog : IEventLog
{

    public void LogData(string log, EventLogType logType)
    {
        Log += logType.Type + ": " + log;
    }

    public string Log { get; set; }
}

public abstract class EventLogType
{
    public abstract string Type
    {
        get;
    }
}


public class TraceLogType : EventLogType
{
    public override string Type { 
        get 
        { 
            return "TRACE"; 
        } 
    }
}

public class ErrorLogType : EventLogType
{
    public override string Type
    {
        get { return "ERROR"; }

    }
}

Sembra che il sovraccarico per un così piccolo esempio di dover definire un nuovo ErrorLogType e istanziarlo ogni volta per l'uso è un po 'troppo.

    
posta Dan W 10.11.2016 - 04:55
fonte

3 risposte

2

Se l'intento è di essere in grado di aggiungere un "prefisso personalizzato" a un messaggio, la soluzione del mondo reale sarebbe qualcosa del tipo:

logger.LogData(String.Format("{0} {1}", prefix, message));

Non c'è una buona ragione per essere più fantasiosi di così. Usare enum non ha molto senso dal momento che un enum ha lo scopo di limitare i valori e si desidera qualcosa di aperto. Definire una classe solo per questo è ancora peggio.

D'altra parte, se non si desidera un prefisso personalizzato ma in realtà si desidera un livello log personalizzato, è un'altra questione. La soluzione del mondo reale è: non farlo. Esistono troppi sistemi esterni (ad esempio aggregatori di registri come SPLUNK o dipendenti nel centro di comando delle operazioni) che si basano su tali valori.

Se ritieni che i livelli di log standard non funzionino per la tua organizzazione (e sia disposto a formare tutti i tuoi nuovi livelli fantasiosi e personalizzi tutte le tue infrastrutture di registrazione e avviso), creane di nuovi e hardcode . Sì, li hardcode. I livelli di log sono parte di un'interfaccia logica e ovviamente non si codificherà mai una definizione di interfaccia, perché ciò vanificherebbe l'intero scopo di avere un'interfaccia.

Se hai bisogno di un modo per includere testo personalizzato nei tuoi messaggi di log, l'interfaccia [codificata] può includere alcuni campi flessibili, ad es. un parametro di stringa a mano libera che viene inserito in una parte predeterminata del messaggio, se si ritiene che valga la complessità aggiuntiva e sia necessario inserire il testo personalizzato nella stessa posizione ogni volta.

L'idea che i tuoi singoli sviluppatori debbano avere la capacità di definire i livelli di log personalizzati al volo mentre programmano, e inoltre che dovrebbe essere facile, è IMO completamente sbagliato. Hanno bisogno di imparare a collegarsi entro i limiti che sono stati dati. Se è veramente necessario un ulteriore livello di log, dovrebbe essere difficile da aggiungere, perché lo si vuole fatto solo molto raramente e in linea con altri sistemi o personale che potrebbero dipendere da esso.

    
risposta data 09.01.2017 - 20:50
fonte
0

Questo potrebbe essere un buon inizio. Quindi qualsiasi implementazione specifica può nascondere i dettagli di come sta registrando e formattando i messaggi che sta registrando.

public enum MessageType
{
    Debug,
    Info,
    Warning,
    Error
}

public interface Logger
{
    void Log(string message, MessageType messageType);       
    void Log(Exception exception); //Assume message or error for exceptions.
}

public interface IMessageFormatter
{
     string Format(string message, MessageType messageType);
}
    
risposta data 10.11.2016 - 17:04
fonte
0

Propongo di creare una classe Trace statica in questi casi, che può essere condivisa tra i progetti. Quella classe può istanziare il IEventLog appropriato nella tua specifica. Una classe di questo tipo può avere metodi come TraceError o TraceInfo (scegliere nomi appropriati).

Tieni presente che un pattern di questo tipo rimuoverà anche la dipendenza del codice utente da TraceLogType e ErrorLogType , il che è positivo perché puoi modificare le implementazioni concrete in seguito.

Ciò consente di utilizzare i file di configurazione affinché la classe Trace cambi l'istanza effettiva di IEventLog in base alla configurazione. Tecnicamente, puoi basarlo come un modello di strategia. Anche se l'istanza IEventLog è incorporata nel codice della classe Trace , può essere modificata senza modificare tutto il codice chiamante.

Questo modello eviterà anche l'inizializzazione di TraceLogType, ErrorLogType e IEventLog in più punti nel codice del consumatore.

Per il tuo esempio, questo è ciò che potrebbe sembrare una classe:

public static class Trace
{
    private static IEventLog logger = new StandardEventLog();
    private static TraceLogType traceLogType = new TraceLogType();
    private static ErrorLogType errorLogType = new ErrorLogType();

    public static void LogTrace(string message)
    {
        eventLog.LogData(message, traceLogType);
    }

    public static void LogError(string message)
    {
        eventLog.LogData(message, errorLogType);
    }
}

Ciò consente di modificare praticamente tutto ciò che riguarda le classi di registrazione senza influire sul codice chiamante. Ma se è necessario passare una decisione su come inizializzare la traccia, uno schema addizionale è quello di aggiungere un metodo Initialize che possa prendere i parametri appropriati per prendere decisioni su come inizializzarsi.

    
risposta data 25.01.2017 - 07:23
fonte

Leggi altre domande sui tag