Saya dulu menggunakan fasad logging seperti Common.Logging (bahkan untuk menyembunyikan library CuttingEdge.Logging saya sendiri ), tetapi saat ini saya menggunakan pola Dependency Injection dan ini memungkinkan saya untuk menyembunyikan logger di balik abstraksi saya sendiri (sederhana) yang menganut kedua Dependency Prinsip Inversi dan Prinsip Segregasi Antarmuka(ISP) karena memiliki satu anggota dan karena antarmuka ditentukan oleh aplikasi saya; bukan perpustakaan eksternal. Meminimalkan pengetahuan yang dimiliki bagian inti aplikasi Anda tentang keberadaan perpustakaan eksternal, semakin baik; bahkan jika Anda tidak berniat untuk mengganti perpustakaan logging Anda. Ketergantungan keras pada pustaka eksternal mempersulit pengujian kode Anda, dan memperumit aplikasi Anda dengan API yang tidak pernah dirancang secara khusus untuk aplikasi Anda.
Ini adalah abstraksi yang sering terlihat dalam aplikasi saya:
public interface ILogger
{
void Log(LogEntry entry);
}
public enum LoggingEventType { Debug, Information, Warning, Error, Fatal };
public class LogEntry
{
public readonly LoggingEventType Severity;
public readonly string Message;
public readonly Exception Exception;
public LogEntry(LoggingEventType severity, string message, Exception exception = null)
{
if (message == null) throw new ArgumentNullException("message");
if (message == string.Empty) throw new ArgumentException("empty", "message");
this.Severity = severity;
this.Message = message;
this.Exception = exception;
}
}
Secara opsional, abstraksi ini dapat diperluas dengan beberapa metode ekstensi sederhana (memungkinkan antarmuka tetap sempit dan tetap mengikuti ISP). Ini membuat kode untuk konsumen antarmuka ini jauh lebih sederhana:
public static class LoggerExtensions
{
public static void Log(this ILogger logger, string message) {
logger.Log(new LogEntry(LoggingEventType.Information, message));
}
public static void Log(this ILogger logger, Exception exception) {
logger.Log(new LogEntry(LoggingEventType.Error, exception.Message, exception));
}
}
Karena antarmuka hanya berisi satu metode, Anda dapat dengan mudah membuat ILogger
implementasi yang merupakan proxy ke log4net , untuk Serilog , Microsoft.Extensions.Logging , NLog atau perpustakaan logging lain dan mengkonfigurasi kontainer DI Anda untuk menyuntikkan itu di kelas yang memiliki ILogger
di mereka konstruktor.
Perhatikan bahwa memiliki metode ekstensi statis di atas antarmuka dengan metode tunggal sangat berbeda dari memiliki antarmuka dengan banyak anggota. Metode ekstensi hanyalah metode pembantu yang membuat LogEntry
pesan dan meneruskannya melalui satu-satunya metode pada ILogger
antarmuka. Metode ekstensi menjadi bagian dari kode konsumen; bukan bagian dari abstraksi. Hal ini tidak hanya memungkinkan metode ekstensi berkembang tanpa perlu mengubah abstraksi, metode ekstensi, dan ekstensiLogEntry
konstruktor selalu dieksekusi ketika abstraksi pencatat digunakan, bahkan ketika pencatat tersebut dihentikan / diolok-olok. Ini memberikan lebih banyak kepastian tentang kebenaran panggilan ke logger saat menjalankan rangkaian pengujian. Antarmuka satu anggota membuat pengujian lebih mudah juga; Memiliki abstraksi dengan banyak anggota mempersulit pembuatan implementasi (seperti tiruan, adaptor, dan dekorator).
Saat Anda melakukan ini, hampir tidak pernah ada kebutuhan untuk beberapa abstraksi statis yang mungkin ditawarkan oleh fasad logging (atau pustaka lainnya).