Продолжаем разбор прошлой темы.
Можно выделить три способа для внедрения зависимости в объект:
1. Constructor Injection. Зависимости передаются классу через его конструктор;
2. Property Injection. Зависимости передаются классу через публичные свойства после создания объекта. Способ предоставляет необязательные зависимости и позволяет менять их во время выполнения без создания новых экземпляров;
3. Method Injection. Зависимость вводится в метод, который будет её использовать.
Идея же Ambient Context заключается в создании публичного статического свойства или метода, предоставляющих экземпляр объекта определённого типа и доступного любому объекту в приложении. Паттерн позволяет предоставлять зависимости функциям, не передавая их явно в качестве параметров. Он особенно полезен для обработки сквозных задач в функциональном стиле.
Предположим, у нас есть класс логирования со следующей функцией:
public static class Logger
{
public static void Print(string message)
{
string data = $"[{DateTime.Now}] {message}";
Console.WriteLine(data);
}
}
Представим, что мы хотим иметь возможность изменять способ логирования (например, записывать в файл) без изменения сигнатуры функции Print. Решить такую задачу можно примерно следующим кодом:
public static class Logger
{
public static Action
static Logger() => sync = new();
private static Action
private static readonly object sync;
public static void Print(string message)
{
lock (sync)
{
string data = $"[{DateTime.Now}] {message}";
(_printHandler ?? Console.WriteLine)(data);
}
}
}
Используем:
Logger.PrintHandler = (msg) => File.AppendAllText("Log.txt", $"{msg}\r\n");
Logger.Print("This message will be written to file!");
Logger.PrintHandler = null;
Logger.Print("This message will be printed to console!");
Добавив делегат PrintHandler, отвечающий за сквозную реализацию, любой источник извне может корректировать реализацию метода Print. Если обработчик не трогать, то класс по умолчанию выведет сообщение в консоль. Первое сообщение логируется в файл, второе же будет выведено в консоль.
Гибкость и расширяемость такого способа ясна, а подмена зависимости для тестов сильно упростит тестирование. Однако есть и минусы: сложность в отслеживании реализации зависимости, понимание кода может быть затруднено и необходимо аккуратно управлять контекстом из-за непредсказуемого поведения.
#Полезно #DependencyInjection #Паттерн