Порождающие паттерны: Factory Method, Abstract Factory, Builder, Singleton (фабрика отчётов)
↑ 8.1 Принципы и паттерны проектирования в C♯ · ← Предыдущая · → Следующая
Зачем это на собесе
Порождающие паттерны спрашивают с примерами из реальной практики и знанием, как DI заменяет часть из них.
Объяснение
| Паттерн | Задача | Пример |
|---|---|---|
| Factory Method | подкласс/метод решает, какой объект создать | ReportFactory.Create(type) |
| Abstract Factory | семейство связанных объектов | UI-темы, провайдеры БД (DbProviderFactory) |
| Builder | пошаговая сборка сложного объекта | WebApplicationBuilder, StringBuilder, SqlBuilder |
| Singleton | единственный экземпляр | в .NET — AddSingleton, а не статическое поле |
| Prototype | клонирование | record с with |
| Object Pool | переиспользование дорогих объектов | ArrayPool, ObjectPool<T> |
// Factory: выбор отчёта по типу; зависимости приходят из DI
public interface IReport { string Type { get; } Task<byte[]> BuildAsync(ReportRequest r, CancellationToken ct); }
public class ReportFactory(IEnumerable<IReport> reports)
{
private readonly Dictionary<string, IReport> _map = reports.ToDictionary(r => r.Type);
public IReport Create(string type) => _map.TryGetValue(type, out var r) ? r : throw new NotSupportedException(type);
}
// регистрация: services.AddScoped<IReport, InvoiceReport>(); ... — новый отчёт = новый класс (OCP)
// Builder
var order = new OrderBuilder().ForCustomer(c).WithItem(sku, 2).WithDiscount(10).Build();
// Singleton: потокобезопасная ленивая инициализация
public sealed class Config { private static readonly Lazy<Config> _i = new(() => new Config()); public static Config Instance => _i.Value; }В приложениях с DI вместо ручного Singleton используйте регистрацию AddSingleton: проще тестировать и заменять.
Нюансы и подводные камни
- Классический Singleton — глобальное состояние: скрытые зависимости, проблемы в тестах и потокобезопасности.
- Фабрика с
switchнарушает OCP; регистрация реализаций в DI и словарь по ключу — гибче (см. keyed services). - Builder без валидации в
Build()создаёт невалидные объекты. - Избыточные фабрики там, где достаточно конструктора.
Практика
- Реализуйте фабрику отчётов на DI (
IEnumerable<IReport>). - Сделайте fluent-Builder для сложного объекта с валидацией.
- Замените статический Singleton на DI-singleton.
Вопросы с ответами
Factory Method или Abstract Factory?
Factory Method создаёт один продукт, Abstract Factory — семейство согласованных продуктов.
Почему Singleton называют антипаттерном?
Глобальное изменяемое состояние, скрытые зависимости, трудности тестирования; в DI используют управляемое время жизни.