Hier ist ein Problem, mit dem ich schon seit ich angefangen habe, objektorientierte Programmierung zu lernen: Wie sollte man einen Logger im "richtigen" OOP-Code implementieren?
Damit meine ich ein Objekt mit einer Methode, auf die jedes andere Objekt im Code zugreifen soll. Diese Methode würde in der 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 das dem Professor erzählte, 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 jedoch letztlich suche, ist das Wissen, wie ich dies richtig und in der OOP Weise selbst umsetzen kann.Sie tun möchten den Logger als globale Variable einrichten, weil globale Variablen nicht schlecht sind. 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.
Es gibt einige sehr durchdachte Lösungen. Einige beinhalten die Umgehung von OO und die Verwendung eines anderen Mechanismus (AOP).
Logging eignet sich nicht wirklich gut für OO (was in Ordnung ist, nicht alles). Wenn Sie es selbst implementieren müssen, schlage ich vor, "Log" am Anfang jeder Klasse zu instanziieren:
privates endgültiges Protokoll = neues Protokoll (dies);
und all Ihre Protokollierungsaufrufe sind dann trivial: log.print ("Hey");
Das macht es viel einfacher zu benutzen 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 log haben, können Sie dann Folgendes tun:
log.addTag ("Rechnung");
Und log 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.
Ein global zugänglicher Logger ist ein schmerzhafter Test. 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 in etwa so aussehen:
%Vor%Wie ersetzen Sie es durch einen Schein?
Besser:
%Vor%Ich habe immer das Singleton-Muster verwendet, um ein Protokollierungsobjekt zu implementieren.
Ich denke, dass Sie dafür AOP (aspektorientierte Programmierung) anstelle von OOP verwenden sollten.
In der Praxis funktioniert meiner Meinung nach eine Singleton / Global-Methode 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.
Achten Sie jedoch auf Überdimensionierung, ich finde, dass in der Praxis eine einzelne Klasse mit nur globalen Methoden recht gut funktionieren kann.
Oder Sie können die Infrastruktur verwenden, in der das jeweilige Framework, in dem Sie arbeiten, anbietet.
Der Enterprise Library-Protokollierungs-Anwendungsblock , der von Microsofts Pattern & amp; Die Practices-Gruppe ist ein großartiges Beispiel für die Implementierung eines Logging-Frameworks in einer OOP-Umgebung. Sie haben eine großartige Dokumentation darüber, wie sie ihren Logging-Anwendungsblock implementiert haben und der gesamte Quellcode für Ihre eigene Überprüfung oder Modifikation verfügbar ist.
Es gibt andere ähnliche Implementierungen: log4net, log4j, log4cxx
Sie haben den Enterprise Library Logging Application Block so implementiert, dass sie eine statische Logger
-Klasse mit einer Reihe verschiedener Methoden haben, die die Protokolloperation tatsächlich ausführen. Wenn Sie sich Muster anschauten, wäre dies wahrscheinlich eine der besseren Anwendungen des Singleton-Musters.
Ich bin alles für AOP zusammen mit log4 *. Das hat uns wirklich geholfen. Google hat mir beispielsweise diesen Artikel gegeben. Sie können versuchen, mehr zu diesem Thema zu suchen.
(IMHO) Wie "Protokollierung" passiert, ist nicht Teil Ihres Lösungsdesigns, 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 den Weg hier hier nachsehen Ein Beispiel dafür, wie Sun es angepackt hat, da sie wahrscheinlich ein ziemlich gutes Design entwickelt haben und alles für Sie bereitstellten!
verwendet eine statische Klasse, hat den geringsten Overhead und ist von allen Projekttypen innerhalb einer einfachen Assembly-Referenz zugänglich
Beachten Sie, dass ein Singleton äquivalent ist, aber eine unnötige Zuweisung beinhaltet
Wenn Sie mehrere Anwendungsdomänen verwenden, müssen Sie darauf achten, dass Sie möglicherweise ein Proxy-Objekt benötigen, um von anderen Domänen als der Hauptdomäne auf die statische Klasse zuzugreifen
Auch wenn Sie mehrere Threads haben, müssen Sie möglicherweise die Protokollierungsfunktionen sperren, um eine Verschachtelung der Ausgabe zu vermeiden
IMHO Logging allein reicht nicht aus, deshalb habe ich CALM
geschriebenviel Glück!
Das Einfügen von Logging auf transparente Art und Weise würde eher in das Aspect-orientierte Programmier-Idiom gehören. Aber wir reden OO Design hier ...
Das Singleton-Muster ist meiner Meinung nach am nützlichsten: Sie können auf den Protokollierungsdienst von jedem Kontext aus über eine öffentliche, statische Methode einer LoggingService-Klasse zugreifen.
Obwohl dies einer globalen Variablen sehr ähnlich zu sein scheint, ist es das nicht: Es ist in der Singleton-Klasse richtig gekapselt, und nicht jeder hat Zugriff darauf. Auf diese Weise können Sie die Protokollierung auch zur 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.
Ich habe dies in der Vergangenheit gelöst, indem ich eine Instanz einer Protokollierungsklasse zur Basisklasse (oder zur 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.
Dies bewirkt einen erheblichen Mehraufwand, daher ist es nicht unbedingt eine kluge Wahl für die Produktionsprotokollierung, aber Aspekte des Loggers können bedingt deaktiviert werden, wenn Sie es so entwerfen.
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 habe, die ich vorteilhaft finde. Die Vorteile eines robusten Logging-Systems, bei dem jemand anderes bereits viel Zeit mit Debugging 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, die permgen Speicherprobleme verursachen (zumindest denke ich , das ist das Problem), also werde ich wahrscheinlich bald Logger wieder besuchen.
Um globale Variablen zu vermeiden, schlage ich vor, eine globale REGISTRIERUNG zu erstellen und Ihre Globals dort zu registrieren.
Für die Protokollierung bevorzuge ich die Bereitstellung einer Singleton-Klasse oder einer Klasse, die statische Methoden für die Protokollierung bereitstellt.
Eigentlich würde ich eines der vorhandenen Logging-Frameworks verwenden.
Eine andere mögliche Lösung ist eine Log-Klasse, die die Logging / Stored-Prozedur kapselt. Auf diese Weise können Sie ein new Log();
immer dann instanziieren, wenn Sie es benötigen, ohne ein Singleton verwenden zu müssen.
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 auch eine globale oder statische Protokollierungsklasse / -funktion vollständig vermeiden.
Tags und Links language-agnostic logging oop