“Патерн Вівторка” #6: Фабричний метод (Factory Method)
|Уявіть, що ваша аплікація є дуже складною і так склалося, що ви використовуєте два логінг провайдери – один Log4Net та інший Enterprise.Logging. Ваш колега догадався помістити вибір провайдера прямо у конфіг файл. Так як ви всю логіку логування абстрагуєте за інтерфейсом ILogger, то вам б також хотілося приховати специфіку створення конкретного провайдера та винести її в окремий клас.
Як на мене то цей дизайн патерн є одним із найбільш відомих і найпростіших. Я переконаний, що більшість читачів бачили його багато раз. Завдання Фабричного Методу полягає в прихованні конкретного класу, що має бути створений та повернений під виглядом спільної абстракції. Якщо в метод передаються параметри, від яких залежить який клас буде створено, то такий Фабричний Метод називають Параметризованим Фабричним Методом.
В нашому прикладі, класи що мають бути створені є Log4NetLogger та EnterpriseLogger, які імплементують ILogger, який широко використовується у нас в аплікації.
public interface ILogger
{
void LogMessage(string message);
void LogError(string message);
void LogVerboseInformation(string message);
}
Як можна здогадуватися, може статися що в майбутньому нам знадобиться додати ще декілька провайдерів логування (мало чого). Як ми уже згадували вирішення приймається на основі того, що є у файлі конфігурації. Щоб не показувати, який клас ми створюємо ми делегуємо цю роботу до LoggerProviderFactory. Ось використання:
public static void Run()
{
var providerType = GetTypeOfLoggingProviderFromConfigFile();
ILogger logger = LoggerProviderFactory.GetLoggingProvider(providerType);
logger.LogMessage("Hello Factory Method Design Pattern.");
}
private static LoggingProviders GetTypeOfLoggingProviderFromConfigFile()
{
return LoggingProviders.Log4Net;
}
То що ж ми отримуємо від методу GetLoggingProvider є об’єктом реалізуючим потрібний інтерфейс. Фабричний Метод вирішує яикй із конкретних класів створювати на основі вхідного параметру, в нашому випадку це енам.
А ось реалізація Фабричного Методу:
public class LoggerProviderFactory
{
public static ILogger GetLoggingProvider(LoggingProviders logProviders)
{
switch (logProviders)
{
case LoggingProviders.Enterprise:
return new EnterpriseLogger();
case LoggingProviders.Log4Net:
return new Log4NetLogger();
default:
return new EnterpriseLogger();
}
}
}
Оскільки моя хардкоджена конфігурація повертає Log4Net і оскільки імплементація методу LogMessage виглядає приблизно так:
public void LogMessage(string message)
{
Console.WriteLine(string.Format("{0}: {1}", "Log4Net", message));
}
Я отримую наступний вивід:
Log4Net: Hello Factory Method Design Pattern.