← Назад к вопросам

Что такое паттерн Builder?

1.0 Junior🔥 161 комментариев
#Архитектура и микросервисы#ООП и паттерны проектирования

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Паттерн Builder (Строитель)

Паттерн Builder — это порождающий шаблон проектирования, который позволяет создавать сложные объекты пошагово, отделяя конструирование объекта от его представления. Основная цель — упростить процесс создания объектов с большим количеством параметров, особенно когда некоторые параметры являются опциональными или имеют сложные зависимости.

Проблема, которую решает Builder

Представьте класс Product с множеством полей:

public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
    public int Quantity { get; set; }
    public string Category { get; set; }
    public string Manufacturer { get; set; }
    public DateTime? ExpiryDate { get; set; }
    public bool IsDiscounted { get; set; }
    // ... ещё 10 свойств
}

Создание объекта через конструктор становится кошмаром:

var product = new Product("Name", 100.0m, 10, "Electronics", "Manufacturer", 
                          new DateTime(2025, 12, unfold), true, /* ... ещё 10 параметров */);

Альтернативы и их недостатки:

  • Перегруженные конструкторы — приводят к "взрыву комбинаций" конструкторов
  • Set-методы после создания — объект может находиться в неконсистентном состоянии
  • Инициализаторы объектов — лучше, но всё равно не решают проблему валидации и порядка инициализации

Решение через Builder

Паттерн предлагает вынести логику конструирования в отдельный класс-строитель:

public class ProductBuilder
{
    private Product _product = new Product();
    
    public ProductBuilder WithName(string name)
    {
        _product.Name = name;
        return this;
    }
    
    public ProductBuilder WithPrice(decimal price)
    {
        _product.Price = price;
        return this;
    }
    
    public ProductBuilder WithCategory(string category)
    {
        _product.Category = category;
        return this;
    }
    
    // ... методы для других свойств
    
    public Product Build()
    {
        // Валидация и финальная логика
        if (string.IsNullOrEmpty(_product.Name))
            throw new InvalidOperationException("Name is required");
        
        if (_product.Price <= 0)
            throw new InvalidOperationException("Price must be positive");
            
        return _product;
    }
}

Использование с Fluent Interface:

var product = new ProductBuilder()
    .WithName("Smartphone")
    .WithPrice(999.99m)
    .WithCategory("Electronics")
    .WithManufacturer("Apple")
    .Build();

Ключевые компоненты Builder

  1. Продукт (Product) — сложный объект, который нужно создать
  2. Строитель (Builder) — интерфейс/абстрактный класс с методами для построения частей продукта
  3. Конкретный строитель (Concrete Builder) — реализация интерфейса Builder
  4. Директор (Director, опционально) — класс, который определяет порядок шагов построения

Реализация с директором

public interface IProductBuilder
{
    IProductBuilder WithName(string name);
    IProductBuilder WithPrice(decimal price);
    IProductBuilder WithCategory(string category);
    Product Build();
}

public class ElectronicsProductBuilder : IProductBuilder
{
    private Product _product = new Product();
    
    public IProductBuilder WithName(string name)
    {
        _product.Name = name + " (Electronics)";
        return this;
    }
    
    // ... специфичная для электроники логика
}

public class ProductDirector
{
    private readonly IProductBuilder _builder;
    
    public ProductDirector(IProductBuilder builder)
    {
        _builder = builder;
    }
    
    public Product ConstructPremiumProduct()
    {
        return _builder
            .WithName("Premium Device")
            .WithPrice(1999.99m)
            .WithCategory("Premium")
            .Build();
    }
}

Преимущества паттерна Builder

  • Пошаговое конструирование — объект создаётся постепенно, шаг за шагом
  • Изоляция сложной логики создания — код создания не загрязняет основной класс продукта
  • Гибкость — можно создавать разные представления объекта, используя один и тот же процесс построения
  • Читаемость кода — fluent interface делает код создания объектов самодокументируемым
  • Неизменяемость (Immutability) — легко сделать продукт неизменяемым, так как все свойства устанавливаются перед созданием
  • Валидация — централизованная проверка корректности объекта в методе Build()

Недостатки

  • Усложнение кода — требуется создание дополнительных классов
  • Избыточность для простых объектов — не стоит использовать для объектов с 2-3 свойствами

Применение в C# Backend

В бэкенд-разработке на C# Builder особенно полезен:

  1. Конфигурация — построение объектов конфигурации (например, DbContextOptionsBuilder в EF Core)
  2. HTTP-запросы — построение сложных запросов к API
  3. Query Building — построение SQL-запросов или запросов к NoSQL базам
  4. Domain-Driven Design — создание агрегатов и value objects со сложными инвариантами
  5. Тестирование — создание тестовых данных с разными комбинациями свойств

Пример из .NET Ecosystem

Классический пример — StringBuilder:

var sb = new StringBuilder();
sb.Append("Hello")
  .Append(" ")
  .Append("World")
  .AppendLine()
  .AppendFormat("Today is {0}", DateTime.Now);
string result = sb.ToString();

Entity Framework Core использует Builder Pattern для конфигурации:

var options = new DbContextOptionsBuilder<MyContext>()
    .UseSqlServer(connectionString)
    .EnableSensitiveDataLogging()
    .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
    .Options;

Best Practices

  • Используйте method chaining (возврат this) для fluent interface
  • Добавляйте валидацию в метод Build()
  • Рассмотрите статический фабричный метод для начала построения:
    public static ProductBuilder Create() => new ProductBuilder();
    
  • Для очень сложных объектов используйте директор для стандартных конфигураций

Builder Pattern — это мощный инструмент для управления сложностью создания объектов, который особенно ценен в enterprise-приложениях, где объекты часто имеют десятки свойств и сложные бизнес-правила валидации.