Non penso che quello che stai descrivendo sia necessariamente strettamente accoppiato
This of course couples the logging library with other code - other code still has to be aware of how the logging library works (that it wants the string, name, & level)
Non esattamente. Il codice che consuma non ha bisogno di sapere in che modo la libreria di registrazione funziona. Dovrà semplicemente sapere cosa è previsto di una libreria di registrazione. In altre parole, il codice di consumo deve solo conoscere l' interfaccia pubblica della libreria di log
.
Se la tua lingua lo supporta, puoi garantire un accoppiamento più sciolto costringendo il codice che consuma a funzionare contro un'interfaccia di Logger (al contrario dell'implementazione di Logger).
Questo è considerato in modo approssimativo perché esiste solo un punto di contatto chiaramente definito tra la libreria Logger e il codice che consuma. Questa è l'interfaccia del logger.
Se in futuro hai deciso di sostituire il tuo Logger con un nuovo logger moderno, allora tutto quello che dovresti fare è codificare un livello di compatibilità tra il tuo nuovo Logger lib e la tua interfaccia Logger esistente. Accoppiamento lento al massimo;)
In C #:
La tua interfaccia del logger:
public interface ILogger
{
void Log(String filename, String message, Level level);
void Log(String filename, Exception exception, Level level);
void Log(String message, Level level);
void Log(Exception exception, Level level);
void LogInfo(String message);
void LogWarning(String message);
void LogError(String error);
void LogError(Exception error);
// etc...
}
Un'implementazione specifica di ILogger
public class AbcLogger : ILogger
{
// Implements all of ILogger
public void LogWarning(String message)
{
this.abcTarget.Write(message, AbcLevelsEnum.Warning)
}
}
Codice che consuma un Logger
public void SomeMethod(int a)
{
if (a < 1000)
{
String message = "Quantities of fewer than 1000 bananas are not accepted";
ILogger logger = ServiceLocator.GetMeMyLogger();
logger.LogWarning(message);
throw new BananaException(message);
}
// do more...
}
Come puoi vedere, il codice che consuma non sa che si tratta di AbcLogger
. Tutto ciò che sa è che un logger è disponibile e che può essere utilizzato aprendo l'interfaccia ILogger
.
E in questo modo, se vuoi passare a un altro registratore come questo ...
public class XyzLogger : ILogger
{
// Implements all of ILogger
public void LogWarning(String message)
{
this.xyzTarget.Flush();
this.xyzTarget.OtherPreRequisites();
this.xyzTarget.Write(message, XyzLevel.NonCritical)
this.xyzTarget.Flush();
this.xyzTarget.OtherPostRequisites();
}
}
... è solo questione di modificare il codice di bootstrap dell'applicazione per utilizzare XyzLogger
anziché AbcLogger
.
public Bootstrapping()
{
ServiceLocator.SetLogger(new XyzLogger());
ServiceLocator.SetBananaManager(new BananaManaga());
// ... etc
}