Порождающие паттерны: Factory Method, Abstract Factory, Builder, Singleton (фабрика отчётов)

↑ 8.1 Принципы и паттерны проектирования в C♯ · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: senior

Зачем это на собесе

Порождающие паттерны спрашивают с примерами из реальной практики и знанием, как 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() создаёт невалидные объекты.
  • Избыточные фабрики там, где достаточно конструктора.

Практика

  1. Реализуйте фабрику отчётов на DI (IEnumerable<IReport>).
  2. Сделайте fluent-Builder для сложного объекта с валидацией.
  3. Замените статический Singleton на DI-singleton.

Вопросы с ответами

Связанные темы