2008-09-17 9 views
8

Hier ist ein Problem, mit dem ich seit meiner ersten objektorientierten Programmierung Probleme habe: Wie sollte man einen Logger in "korrektem" OOP-Code implementieren?Ordnungsgemäße Anmeldung im OOP-Kontext

Damit meine ich ein Objekt, das eine Methode hat, auf die jedes andere Objekt im Code zugreifen soll; Diese Methode würde auf Konsole/Datei/was auch immer ausgeben, die wir für die Protokollierung verwenden würden - daher wäre dieses Objekt das Logger-Objekt.

Wir wollen das Logger-Objekt nicht als globale Variable etablieren, weil globale Variablen schlecht sind, oder? Aber wir wollen auch nicht, dass das Logger-Objekt in den Parametern jeder einzelnen Methode übergeben wird, die wir in jedem einzelnen Objekt aufrufen.

In der Schule, als ich dies auf den Professor brachte, konnte er mir eigentlich keine Antwort geben. Ich weiß, dass es tatsächlich Pakete gibt (zum Beispiel Java), die diese Funktionalität implementieren könnten. Was ich aber letztlich suche, ist das Wissen, wie ich es richtig und in der OOP-Weise selbst umsetzen kann.

Antwort

13

Sie wollen Sie den Logger als globale Variable zu etablieren, weil globale Variablen sind nicht schlecht. Zumindest sind sie nicht von Natur aus schlecht. Ein Logger ist ein großartiges Beispiel für die ordnungsgemäße Verwendung eines global zugänglichen Objekts. Lesen Sie mehr über das Singleton-Entwurfsmuster, wenn Sie weitere Informationen benötigen.

+1

Ich hätte es nicht besser sagen können. –

0

Sie könnten das Singleton-Muster betrachten.

0

Erstellen Sie den Logger als Singleton-Klasse und greifen Sie dann mit einer statischen Methode darauf zu.

1

Ich habe immer das Singleton-Muster verwendet, um ein Protokollierungsobjekt zu implementieren.

+1

Wer hat das abgelehnt? Warum? –

0

Ich denke, dass Sie dafür AOP (aspektorientierte Programmierung) statt OOP verwenden sollten.

0

In der Praxis funktioniert eine Singleton/Global-Methode meiner Meinung nach gut. Vorzugsweise ist das globale Ding nur ein Rahmenwerk, mit dem Sie verschiedene Listener (Beobachtermuster) verbinden können, z. eine für die Konsolenausgabe, eine für die Datenbankausgabe, eine für die Windows-EventLog-Ausgabe usw.

Vorsicht vor Überentwurf, aber ich finde, dass in der Praxis eine einzelne Klasse mit nur globalen Methoden ganz gut funktionieren kann.

Oder Sie könnten die Infrastruktur verwenden, die das spezielle Framework, in dem Sie arbeiten, bietet.

0

Die Enterprise Library Logging Application Block, die aus Microsofts Pattern & Practices-Gruppe stammt, ist ein großartiges Beispiel für die Implementierung eines Protokollierungsframeworks in einer OOP-Umgebung. Sie haben eine großartige Dokumentation darüber, wie sie ihren Logging-Anwendungsblock implementiert haben, und der gesamte Quellcode ist für Ihre eigene Überprüfung oder Änderung verfügbar.

Es gibt noch andere ähnliche Implementierungen: log4net, log4j, log4cxx

Sie, wie sie die Enterprise Library Logging Application Block implementiert haben, ist eine statische Logger-Klasse mit einer Reihe verschiedener Methoden, die tatsächlich die Log-Funktion ausführen. Wenn Sie sich Muster anschauen, wäre dies wahrscheinlich eine der besseren Anwendungen des Singleton-Musters.

4

Es gibt einige sehr gut durchdachte Lösungen. Einige beinhalten die Umgehung von OO und die Verwendung eines anderen Mechanismus (AOP).

Logging eignet sich nicht wirklich gut zu OO (was in Ordnung ist, nicht alles). Wenn Sie es selbst implementieren müssen, schlage ich vor, "Log" am Anfang jeder Klasse zu instanziieren:

private final log = new Log (this);

und alle Ihre Protokollierungsaufrufe sind dann trivial: log.print ("Hey");

Das macht es viel einfacher zu verwenden als ein Singleton.

Lassen Sie Ihren Logger herausfinden, welche Klasse Sie übergeben und verwenden Sie diese, um das Protokoll zu kommentieren. Da Sie dann eine Instanz von Protokoll haben, können Sie dann Dinge wie tun:

log.addTag ("Bill");

Und Protokoll kann die Tag-Rechnung zu jedem Eintrag hinzufügen, so dass Sie eine bessere Filterung für Ihre Anzeige implementieren können.

log4j und Kettensäge sind eine perfekte Lösung - wenn Sie nicht nur akademisch sind, verwenden Sie diese.

+0

Dadurch können Sie den Logger nicht verspotten, wenn Sie das fragliche Objekt testen.Das bedeutet, wenn sich der Logger beispielsweise bei einem Drittanbieter-Dienst anmeldet, erhalten Sie diese Protokollzeile jedes Mal, wenn Sie das Objekt testen. Ich denke, dass in diesem Fall das Speichern des Loggers in einem Container eine bessere Idee ist, da Sie immer die Container (Singleton) -Instanz dieses Objekts für einen Dummy-Logger ersetzen können. – Bruno

+0

@Bruno In Log4J stellen wir verschiedene Konfigurationsdateien zum Testen bereit, zum Beispiel könnte es während eines Tests in eine Textdatei oder die Konsole für ein bestimmtes Protokoll gehen, aber in der Produktion könnte es in eine Datenbank gehen. Ich habe auch einen Logger an einen Konstruktor übergeben, um das Testen zu vereinfachen. Das Singleton funktioniert auch, aber es wird schwierig, es zu testen/zu ersetzen, wenn es groß wird (und das ist eigentlich nur das Duplizieren der Arbeit, die log4j mit Konfigurationsdateien zur Verfügung stellt). Die beste Wette ist Frühling, aber das kann abhängig von Ihrer Situation übertrieben sein. –

0

Ich bin alles für AOP zusammen mit log4 *. Das hat uns wirklich geholfen. Google gab mir this article zum Beispiel. Sie können versuchen, mehr zu diesem Thema zu suchen.

0

(IMHO) Wie "Protokollierung" passiert, ist nicht Teil Ihres Lösungsentwurfs, es ist mehr Teil der Umgebung, in der Sie gerade laufen - wie System und Kalender in Java.

Ihre "gute" Lösung ist eine, die so locker wie möglich an eine bestimmte Protokollimplementierung gekoppelt ist, also denken Sie an Schnittstellen. Ich würde mir die Spur here ansehen, um ein Beispiel zu geben, wie Sun es angepackt hat, da sie wahrscheinlich ein ziemlich gutes Design entwickelt haben und alles für Sie auslegen, von dem Sie lernen können!

0

Verwendung eine statische Klasse, hat es die am wenigsten Aufwand und ist von allen Projekttypen innerhalb einer einfachen Montage Referenz

Note zugänglich, dass ein Singleton äquivalent ist, beinhaltet aber unnötige Zuweisung

, wenn Sie mehrere verwenden App-Domains, passen sie, dass Sie ein Proxy-Objekt müssen möglicherweise die statische Klasse von anderen Domains als der wichtigste

auch zugreifen, wenn Sie mehrere Threads haben Sie können um die Logging-Funktionen sperren müssen vermeiden Interlacing die Ausgabe

IMHO Logging allein ist nicht ausreichend, deshalb schrieb ich CALM

viel Glück!

0

Vielleicht Einfügen Logging auf eine transparente Art und Weise würde eher in der Aspect Oriented Programmierung Idiom gehören. Aber wir reden OO Design hier ...

Das Singleton-Muster möglicherweise die nützlichste, meiner Meinung nach: Sie können den Logging-Dienst von jedem Kontext über eine öffentliche, statische Methode einer LoggingService-Klasse zugreifen.

Obwohl dies einer globalen Variablen sehr ähnlich zu sein scheint, ist es nicht: Es ist ordnungsgemäß in der Singleton-Klasse eingekapselt, und nicht jeder hat Zugriff darauf. Auf diese Weise können Sie die Protokollierung auch während der Laufzeit ändern, die Protokollierung wird jedoch durch den vilain-Code geschützt.

In dem System, an dem ich arbeite, erstellen wir eine Reihe von Logging 'Singletons', um Nachrichten von verschiedenen Subsystemen unterscheiden zu können. Diese können zur Laufzeit ein-/ausgeschaltet werden, Filter können definiert werden, das Schreiben in eine Datei ist möglich ... Sie nennen es.

0

Ich habe dies in der Vergangenheit gelöst, indem ich eine Instanz einer Protokollierungsklasse zur Basisklasse (oder Schnittstelle, falls die Sprache dies unterstützt) für die Klassen hinzufüge, die auf die Protokollierung zugreifen müssen. Wenn Sie etwas protokollieren, betrachtet der Logger den aktuellen Aufruf-Stack und bestimmt den aufrufenden Code, indem er die richtigen Metadaten über die Logging-Anweisung festlegt (Quellmethode, Codezeile, falls verfügbar, Klasse, die protokolliert wurde usw.) Die Anzahl der Klassen hat Logger und die Logger müssen nicht speziell mit den Metadaten konfiguriert werden, die automatisch ermittelt werden können.

Diese tut hinzufügen erhebliche Overhead, so ist es nicht unbedingt eine kluge Wahl für die Produktion Protokollierung, aber Aspekte des Loggers kann bedingt deaktiviert werden, wenn Sie es so gestalten.

Realistisch verwende ich Commons-Logging die meiste Zeit (ich mache eine Menge Arbeit in Java), aber es gibt Aspekte des Designs, die ich oben beschrieben, dass ich vorteilhaft finde. Die Vorteile eines robusten Logging-Systems, bei dem jemand anderes bereits viel Zeit mit dem Debuggen verbracht hat, haben die Notwendigkeit eines saubereren Designs aufgewogen (das ist natürlich subjektiv, vor allem angesichts des Mangels an Details in diesem Beitrag).

Ich hatte Probleme mit statischen Loggern verursachen Permgen Speicherprobleme (zumindest ich denke, das ist, was das Problem ist), so werde ich wahrscheinlich Logger bald wieder besuchen.

2

Ein global zugänglicher Logger ist ein Testschmerz. Wenn Sie eine "zentralisierte" Protokollierungsfunktion benötigen, erstellen Sie diese beim Programmstart und injizieren Sie sie in die Klassen/Methoden, die protokolliert werden müssen. Wie testen Sie Methoden, die so etwas wie folgt verwenden:

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

Wie man es mit einem Mock ersetzen?

Besser:

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

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

Eine andere mögliche Lösung ist es, eine Log-Klasse zu haben, die die Protokollierung/Stored Procedure kapselt. Auf diese Weise können Sie einfach ein new Log(); instanziieren, wann immer Sie es brauchen, ohne ein Singleton zu verwenden.

Dies ist meine bevorzugte Lösung, da die einzige Abhängigkeit, die Sie injizieren müssen, die Datenbank ist, wenn Sie sich über die Datenbank anmelden. Wenn Sie Dateien potenziell verwenden, müssen Sie keine Abhängigkeiten injizieren. Sie können eine globale oder statische Protokollierungsklasse/-funktion auch vollständig vermeiden.

0

Um globale Variablen zu vermeiden, schlage ich vor, eine globale REGISTRY zu erstellen und Ihre Globals dort zu registrieren.

Für die Protokollierung bevorzuge ich eine Singleton-Klasse oder eine Klasse, die einige statische Methoden für die Protokollierung bietet.

Eigentlich würde ich eines der vorhandenen Logging-Frameworks verwenden.

Verwandte Themen