Ich habe eine Protokollierungsklasse, die von fast überall in der Anwendung aufgerufen werden muss.
Allerdings muss am Anfang der Anwendung mit "welcher Pfad zum Schreiben", "Protokollierungsstufe" und wenn "aktiviert" ist oder nicht aktiviert werden.
Ich möchte diese Parameter nicht jedes Mal angeben oder die Logging-Klasse als Parameter an jedes einzelne Objekt in meiner Anwendung übergeben. Daher verwende ich das Singleton-Muster für die Protokollierung.
In letzter Zeit habe ich viel von eng gekoppelten Klassen gelitten. Ich möchte nicht noch einmal denselben Fehler machen, aber nachdem ich darüber nachgedacht habe, ist das die einzige gute Lösung.
UPDATE:
Ich interessiere mich nicht dafür, dass ich ähnliche Designprobleme aufzeichnen würde. Ich habe das gleiche Dilemma mit einem anderen globalen Einstellungsobjekt, das aus so vielen Klassen verwendet werden muss. Aber es in jeden einzelnen von ihnen zu injizieren macht nur einen schrecklichen Overhead und weniger lesbaren Code.
Was halten Sie von dieser Implementierung und was tun Sie, wenn Sie ähnliche Designentscheidungen treffen?
P.S. Bitte schlagen Sie nicht etwas wie "Log4X-Bibliothek verwenden" usw. vor.
Erstens - könnten Sie den Protokollschreiber als Trace-Listener schreiben und Trace.Write
etc von den Methoden verwenden?
Brauchen Sie hier tatsächlich eine Instanz? Das wäre zum Beispiel nützlich, wenn Sie es als TextWriter
oder ähnlich abstrahieren möchten - aber wenn es sich um einen eigenständigen Singleton handelt, können die Methoden nicht direkt statische Methoden verwenden, zB Log.Write(...)
(anstatt zu übergeben in einer Protokollinstanz)?
Das allgemeine Problem - es hängt von den Typen ab, die die Protokollierung durchführen. Für "manager" (etc) -Klassen könnten Sie die Injection von Abhängigkeiten (Unity, StructureMap usw.) in Betracht ziehen, um dies zu automatisieren. Ich würde normalerweise keine Injektion mit DTOs verwenden.
Auch wenn Sie keine Vorschläge für "log4X verwenden" möchten (obwohl Sie nicht genau sagen, warum Sie das Rad neu erfinden wollen), erscheint es sinnvoll, die getroffenen Entscheidungen zu prüfen durch verschiedene Logging-Bibliotheken.
Nach meiner Erfahrung sind die Probleme der engen Kopplung bei der Protokollierung nicht so relevant - insbesondere möchte ich die Protokollierungsseite meiner App nur selten testen und es macht mir nichts aus, wenn sie sich während der Einheit an der Konsole anmeldet Testen.
Kurz gesagt, das "normale" Muster von:
%Vor%(mit entsprechenden Namensänderungen usw.) ist in seiner Verwendung von statischen Methoden ästhetisch nicht ansprechend, funktioniert aber in der Praxis ziemlich gut. Zumindest war das meine Erfahrung.
Sie können hier wahrscheinlich ein Singleton verwenden. Sie haben eine enge Kopplung zwischen jeder Klasse in der Anwendung und der Logger-Klasse, aber wenn die Logger-Klasse und die globale Einstellungen-Klasse wirklich in jeder Klasse benötigt werden, kann dies akzeptabel sein.
Ich persönlich benutze in diesem Fall die statische Klasse. Die Klasse verfügt über statische Konfigurationsfelder (für das manuelle Experimentieren) und einige Funktionen, um sie mithilfe der Konfiguration aus dem entsprechenden CONFIG-Dateiabschnitt zu füllen.
Dies ist in der Tat sehr ähnlich wie bei DI, da Sie eine neue Konfiguration "injizieren" können. Um die Konfiguration auf das neue Modell zu ändern, ändere ich einfach im .config Dateifeld, das den "aktiven" Konfigurationsabschnitt enthält.
Dies ist einfach zu bedienen, einfach zu warten, und jeder versteht es ... Ich sehe keinen besonderen Nachteil davon ...
Die Protokollierung und Einstellungen werden auf zwei verschiedene Arten gehandhabt. Wenn ich also richtig verstanden habe, war Ihre eigentliche Frage eher mit der Handhabung globaler Einstellungen zwischen Assemblies zu tun.
Im Hinblick auf die Protokollierung sind die Dinge ziemlich klar - die Verwendung eines globalen Singleton ist üblich, obwohl es Ihre Bibliotheken eng an die Protokollbibliothek koppelt. Trace-Listener zu verwenden ist eine noch bessere Lösung IMHO.
Wenn Sie jedoch über Anwendungseinstellungen sprechen, sollten Sie
Ist das ASP.Net? In diesem Fall können Sie das Fehlerereignis in Global.asax verwenden.
Haben Sie für Ihre vielen Abhängigkeiten in Betracht gezogen, ein Abhängigkeits-Injection-Framework zu verwenden?
Aktualisieren
Ich bin mir nicht sicher, welche Auswirkungen die Leistung hat und wie relevant die Leistung für Ihre App ist, aber dieses Framework sieht interessant aus: PostSharp , < a href="http://johnnycoder.com/blog/2009/01/16/caching-with-c-aop-and-postsharp/"> Ein Blogpost darüber .
Möglicherweise können Sie auch das bedingte Attribut nutzen.
Wenn Sie PostSharp verwenden, würde mich interessieren, wie es funktioniert.
Eine Sache, die Sie untersuchen könnten, ist Paket-für-Funktion. Es wird behauptet, dass das Folgen dieser Technik einige Probleme annimmt, die zu einer hohen Kopplung zwischen Klassen führen. Genauer gesagt würde es bedeuten, dass es in jeder Anwendung in Ihrer Anwendung nur eine Klasse gibt, die für die Kommunikation mit dem Konfigurationsanbieter verantwortlich ist (was durchaus Teil einer Konfigurations- / Setup- / Installationsfunktion selbst sein könnte). Das Kopplungsniveau ist immer noch auf der hohen Seite, aber da es gut definiert ist, sollte es managbar sein.
Wenn Sie immer in dieselbe Quelle schreiben, können Sie das Singleton-Muster verwenden.
Wenn Sie jedoch Informationen zu verschiedenen Quellen protokollieren, z. B. in einer Datei oder einem Ereignisprotokoll, erstellen Sie eine andere Instanz der Protokollierungsklasse für eine andere Konfiguration.