Domanda

Ecco un problema con cui ho lottato sin da quando ho iniziato a imparare la programmazione orientata agli oggetti:come si dovrebbe implementare un logger nel codice OOP "corretto"?

Con questo intendo un oggetto che ha un metodo a cui vogliamo che tutti gli altri oggetti nel codice possano accedere;questo metodo verrebbe restituito a console/file/qualunque cosa, che useremmo per la registrazione, quindi questo oggetto sarebbe l'oggetto logger.

Non vogliamo stabilire l'oggetto logger come variabile globale, perché le variabili globali sono dannose, giusto?Ma non vogliamo nemmeno che venga passato l'oggetto logger nei parametri di ogni singolo metodo che chiamiamo in ogni singolo oggetto.

Al college, quando ne parlai al professore, non riuscì a darmi una risposta.Mi rendo conto che in realtà esistono pacchetti (ad esempio Java) che potrebbero implementare questa funzionalità.Ciò che alla fine sto cercando, però, è la conoscenza di come implementarlo correttamente e in modo OOP.

È stato utile?

Soluzione

Voi Fare voglio stabilire il logger come variabile globale, perché le variabili globali lo sono non Cattivo.Almeno, non sono intrinsecamente cattivi.Un logger è un ottimo esempio dell'uso corretto di un oggetto accessibile a livello globale.Leggi il modello di progettazione Singleton se desideri maggiori informazioni.

Altri suggerimenti

Ci sono alcune soluzioni molto ben pensate.Alcuni implicano il bypass dell'OO e l'utilizzo di un altro meccanismo (AOP).

La registrazione non si presta molto bene all'OO (il che va bene, non tutto lo fa).Se devi implementarlo da solo, ti suggerisco semplicemente di istanziare "Log" all'inizio di ogni classe:

log finale privato=nuovo log(questo);

e tutte le tue chiamate di registrazione sono quindi banali:log.print("Ciao");

Il che lo rende molto più facile da usare rispetto a un singleton.

Chiedi al tuo logger di capire quale classe stai passando e usarla per annotare il registro.Dato che hai un'istanza di log, puoi fare cose come:

log.addTag("Fattura");

Inoltre, il registro può aggiungere la fattura del tag a ciascuna voce in modo da poter implementare un filtro migliore per la visualizzazione.

log4j e motosega sono comunque una soluzione perfetta e pronta all'uso: se non sei solo accademico, usali.

Un logger accessibile a livello globale è una seccatura da testare.Se hai bisogno di una struttura di registrazione "centralizzata", creala all'avvio del programma e inseriscila nelle classi/metodi che necessitano di registrazione.Come si testano metodi che utilizzano qualcosa del genere:

public class MyLogger 
{
    public static void Log(String Message) {}
}

Come lo sostituisci con una finta?

Meglio:

public interface ILog 
{
    void Log(String message);
}

public class MyLog : ILog 
{
    public void Log(String message) {}
}

Ho sempre utilizzato il pattern Singleton per implementare un oggetto di registrazione.

Potresti guardare il modello Singleton.

Crea il logger come classe singleton e quindi accedi utilizzando un metodo statico.

Penso che dovresti usare AOP (programmazione orientata agli aspetti) per questo, piuttosto che OOP.

In pratica, secondo me, un metodo singleton/globale funziona bene.Preferibilmente la cosa globale è solo una struttura a cui è possibile connettere diversi ascoltatori (modello osservatore), ad es.uno per l'output della console, uno per l'output del database, uno per l'output del registro eventi di Windows, ecc.

Attenzione però alla progettazione eccessiva, trovo che in pratica una singola classe con solo metodi globali possa funzionare abbastanza bene.

Oppure potresti utilizzare l'infrastruttura offerta dal particolare framework in cui lavori.

IL Blocco applicazione di registrazione della libreria aziendale che proviene dal gruppo Pattern & Practices di Microsoft è un ottimo esempio di implementazione di un framework di registrazione in un ambiente OOP.Hanno un'ottima documentazione su come hanno implementato il blocco dell'applicazione di registrazione e tutto il codice sorgente è disponibile per la tua revisione o modifica.

Esistono altre implementazioni simili: log4net, log4j, log4cxx

Il modo in cui hanno implementato il blocco dell'applicazione di registrazione della libreria aziendale è quello di avere un file statico Logger classe con una serie di metodi diversi che eseguono effettivamente l'operazione di registro.Se stessi guardando i pattern, questo sarebbe probabilmente uno degli usi migliori del pattern Singleton.

Sono tutto per AOP insieme a log4*.Questo ci ha davvero aiutato.Google mi ha dato Questo articolo ad esempio.Puoi provare a cercare di più su quell'argomento.

(IMHO) il modo in cui avviene la "registrazione" non fa parte della progettazione della soluzione, fa più parte dell'ambiente in cui ti trovi in ​​esecuzione, come Sistema e Calendario in Java.

La tua soluzione "buona" è quella che è il più liberamente accoppiata possibile a qualsiasi particolare implementazione di registrazione, quindi pensa alle interfacce.Controllerei il percorso Qui per un esempio di come Sun ha affrontato il problema, dato che probabilmente hanno ideato un design piuttosto buono e hanno preparato tutto in modo che tu potessi imparare!

utilizzare una classe statica, ha il minor sovraccarico ed è accessibile da tutti i tipi di progetto all'interno di un semplice riferimento all'assembly

si noti che un Singleton è equivalente, ma comporta un'allocazione non necessaria

se utilizzi più domini app, fai attenzione che potrebbe essere necessario un oggetto proxy per accedere alla classe statica da domini diversi da quello principale

inoltre, se si dispone di più thread, potrebbe essere necessario bloccare le funzioni di registrazione per evitare l'interlacciamento dell'output

La sola registrazione IMHO non è sufficiente, ecco perché ho scritto CALMA

buona fortuna!

Forse inserire il Logging in modo trasparente preferirebbe appartenere al linguaggio dell'Aspect Oriented Programming.Ma qui stiamo parlando di design OO...

Il modello Singleton può essere il più utile, secondo me:è possibile accedere al servizio Logging da qualsiasi contesto tramite un metodo pubblico e statico di una classe LoggingService.

Sebbene possa sembrare molto simile a una variabile globale, non lo è:è adeguatamente incapsulato nella classe singleton e non tutti vi hanno accesso.Ciò consente di modificare il modo in cui viene gestita la registrazione anche in fase di esecuzione, ma protegge il funzionamento della registrazione dal codice "vilain".

Nel sistema su cui lavoro, creiamo una serie di 'singleton' di Logging, in modo da poter distinguere i messaggi provenienti da diversi sottosistemi.Questi possono essere attivati/disattivati ​​in fase di esecuzione, è possibile definire filtri, è possibile scrivere su file...lo chiami tu.

Ho risolto questo problema in passato aggiungendo un'istanza di una classe di registrazione alle classi base (o all'interfaccia, se il linguaggio lo supporta) per le classi che devono accedere alla registrazione.Quando registri qualcosa, il logger esamina lo stack di chiamate corrente e determina da quello il codice invocante, impostando i metadati corretti sull'istruzione di registrazione (metodo sorgente, riga di codice se disponibile, classe che ha registrato, ecc.). In questo modo un minimo numero di classi hanno logger e i logger non devono essere configurati in modo specifico con i metadati che possono essere determinati automaticamente.

Questo fa aggiunge un notevole sovraccarico, quindi non è necessariamente una scelta saggia per la registrazione della produzione, ma alcuni aspetti del logger possono essere disabilitati in modo condizionale se lo si progetta in questo modo.

Realisticamente, utilizzo la registrazione commons per la maggior parte del tempo (lavoro molto in Java), ma ci sono aspetti del design che ho descritto sopra che trovo utili.I vantaggi di avere un robusto sistema di registrazione su cui qualcun altro ha già dedicato molto tempo al debug hanno superato la necessità di quello che potrebbe essere considerato un design più pulito (questo è ovviamente soggettivo, soprattutto data la mancanza di dettagli in questo post).

Ho avuto problemi con i logger statici che causavano problemi di memoria permanente (almeno I pensare questo è il problema), quindi probabilmente rivisiterò presto i logger.

Per evitare variabili globali, propongo di creare un REGISTRO globale e registrare lì i tuoi valori globali.

Per la registrazione, preferisco fornire una classe singleton o una classe che fornisca alcuni metodi statici per la registrazione.

In realtà, utilizzerei uno dei framework di registrazione esistenti.

Un'altra possibile soluzione è avere una classe Log che incapsula la procedura di registrazione/memorizzata.In questo modo puoi semplicemente istanziare a new Log(); ogni volta che ne hai bisogno senza dover utilizzare un singleton.

Questa è la mia soluzione preferita, perché l'unica dipendenza che devi inserire è il database se stai accedendo tramite database.Se stai utilizzando file potenzialmente non è necessario inserire alcuna dipendenza.Puoi anche evitare completamente una classe/funzione di registrazione globale o statica.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top