Anmelden als Dekorateur vs. Abhängigkeitsinjektion - was ist, wenn ich mich in der Klasse anmelden muss?
(Diese Frage habe ich ursprünglich in @ gestelldieser Kommentar, aber Mark Seemann hat mich gebeten, stattdessen eine neue Frage zu erstellen.)
Ich starte eine neue App (ggf. .NET Core) und versuche gerade zu entscheiden, wie genau die Protokollierung erfolgen soll.
Der allgemeine Konsens scheint zu sein, dass die Protokollierung ein Querschnittsthema ist, daher sollte der Protokollierer nicht direkt in die Klasse injiziert werden, die protokollieren soll.
ft gibt es ein Beispiel wie die folgende Klasse, wienich es zu tun
public class BadExample : IExample
{
private readonly ILogger logger;
public BadExample(ILogger logger)
{
this.logger = logger;
}
public void DoStuff()
{
try
{
// do the important stuff here
}
catch (Exception e)
{
this.logger.Error(e.ToString());
}
}
}
Instead, die Klasse mit der Geschäftslogik sollte nichts über den Logger wissen SRP) und es sollte eine separate Klasse geben, die die Protokollierung durchführt:
public class BetterExample : IExample
{
public void DoStuff()
{
// do the important stuff here
}
}
public class LoggingBetterExample : IExample
{
private readonly IExample betterExample;
private readonly ILogger logger;
public LoggingBetterExample(IExample betterExample, ILogger logger)
{
this.betterExample = betterExample;
this.logger = logger;
}
public void DoStuff()
{
try
{
this.betterExample.DoStuff();
}
catch (Exception e)
{
this.logger.Error(e.ToString());
}
}
}
Wenn einIExample
wird benötigt, der DI-Container gibt eine Instanz von @ zurüLoggingBetterExample
, das @ verwendBetterExample
(enthält die eigentliche Geschäftslogik) unter der Haube.
Blog-Beiträge vonMark Seemann:
nstrumentierung mit Dekorateuren und AbfangjägeDependency Injection ist lose KopplungBlog posten und SO antworten mit Steven:
Mittlerweile ... auf der Kommandoseite meiner ArchitekturWindsor - Transiente Objekte aus dem Container ziehenMeine Frageffensichtlich ist dieLoggingBetterExample
-Ansatz funktioniert nur, solange die Protokollierung außerhalb der eigentlichen Klasse erfolgen kann.
(wie im obigen Beispiel: fange alle Ausnahmen ab, die von @ geworfen werdBetterExample
von außen
Mein Problem ist, dass ich andere Dinge in der aktuellen Klasse protokollieren möchte.
Mark Seemann vermutlich hier dass, wenn jemand dies tun muss, die betreffende Methode möglicherweise auch viel tut.
Wie ich bereits sagte, bin ich in der Planungsphase für eine neue Anwendung, daher muss ich nicht viel Code anzeigen, aber der Anwendungsfall, an den ich gerade denke, sieht ungefähr so aus:
Meine App hat eine Konfigurationsdatei mit einigen optionalen Werten.
Der Benutzer kann die optionalen Werte weglassen, dies ist jedoch eine wichtige Entscheidung.
So möchte ich eine Warnung protokollieren, wenn einige der optionalen Werte fehlen, nur für den Fall, dass dies versehentlich passiert ist.
(Auslassen der Werte ist jedoch völlig in Ordnung, daher kann ich nicht einfach eine Ausnahme auslösen und anhalten)
Das bedeutet, dass ich eine Klasse haben werde, die Konfigurationswerte liest und so etwas tun muss (Pseudocode):
var config = ReadConfigValues("path/to/config.file");
if (config.OptionalValue == null)
{
logger.Warn("Optional value not set!");
}
Gleichgültig obReadConfigValues
ist in dieser oder einer anderen Klasse, ich glaube nicht, dass diese Klasse die SRP verletzen würde.
Ich weiß, dass ich die Konfigurationsdatei in der inneren Klasse lesen kann, aber überprüfe die Werte (und protokolliere die Warnung) im Decorator. Die IMO-Überprüfung des Werts ist jedoch eine Geschäftslogik und keine Infrastruktur. Für mich gehört sie zu derselben Klasse, in der die Konfigurationsdatei gelesen wird.