Ответ
Паттерн Абстрактная фабрика (Abstract Factory) предоставляет интерфейс для создания семейств взаимосвязанных или взаимозависимых объектов без указания их конкретных классов. Он полезен, когда система должна быть независима от способа создания, компоновки и представления её объектов, или когда нужно создавать целые группы объектов, совместимых между собой.
Классический пример: Кросс-платформенный UI (GUI).
Допустим, мы пишем приложение, которое должно выглядеть нативно и на Windows, и на macOS. Кнопки и чекбоксы для этих систем реализованы по-разному.
- Определяем абстрактные продукты (интерфейсы для элементов UI):
// Абстрактная кнопка
public interface IButton
{
void Render();
void OnClick(Action action);
}
// Абстрактный чекбокс
public interface ICheckbox
{
void Render();
bool IsChecked { get; set; }
}
- Создаем конкретные продукты для каждой платформы:
// Реализация для Windows
public class WindowsButton : IButton
{
public void Render() => Console.WriteLine("Отрисована кнопка в стиле Windows");
public void OnClick(Action action) => Console.WriteLine("Нажатие обработано WinAPI");
}
public class WindowsCheckbox : ICheckbox
{
public bool IsChecked { get; set; }
public void Render() => Console.WriteLine($"[{(IsChecked ? 'X' : ' ')}] Чекбокс Windows");
}
// Реализация для macOS
public class MacButton : IButton
{
public void Render() => Console.WriteLine("Отрисована кнопка в стиле macOS");
public void OnClick(Action action) => Console.WriteLine("Нажатие обработано Cocoa");
}
public class MacCheckbox : ICheckbox
{
public bool IsChecked { get; set; }
public void Render() => Console.WriteLine($"[{(IsChecked ? '✓' : ' ')}] Чекбокс macOS");
}
- Определяем абстрактную фабрику (интерфейс для создания семейства):
public interface IUIFactory
{
IButton CreateButton();
ICheckbox CreateCheckbox();
}
- Реализуем конкретные фабрики для каждой платформы:
public class WindowsUIFactory : IUIFactory
{
public IButton CreateButton() => new WindowsButton();
public ICheckbox CreateCheckbox() => new WindowsCheckbox();
}
public class MacUIFactory : IUIFactory
{
public IButton CreateButton() => new MacButton();
public ICheckbox CreateCheckbox() => new MacCheckbox();
}
- Клиентский код работает только с абстракциями:
public class Application
{
private readonly IButton _button;
private readonly ICheckbox _checkbox;
// Приложение получает фабрику через конструктор (Dependency Injection)
public Application(IUIFactory factory)
{
_button = factory.CreateButton();
_checkbox = factory.CreateCheckbox();
}
public void RenderUI()
{
_button.Render();
_checkbox.Render();
}
}
- Использование: Конкретная фабрика выбирается на этапе конфигурации приложения (например, на основе операционной системы).
// Где-то в точке входа (Program.cs, Main)
IUIFactory factory;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
factory = new WindowsUIFactory();
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
factory = new MacUIFactory();
else
throw new PlatformNotSupportedException();
var app = new Application(factory);
app.RenderUI(); // Отрисует набор элементов для текущей ОС
Преимущества паттерна:
- Гарантирует совместимость объектов:
WindowsButtonвсегда будет создан вместе сWindowsCheckbox. - Изолирует конкретные классы: Клиентский код (
Application) не знает о существованииWindowsButtonилиMacButton. - Упрощает поддержку новых семейств: Чтобы добавить поддержку Linux, нужно создать
LinuxButton,LinuxCheckboxиLinuxUIFactory, не изменяя существующий клиентский код.
Отличие от Фабричного метода: Абстрактная фабрика создает семейство продуктов, а Фабричный метод — один продукт.