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

Какие шаблоны проектирования используешь для backend?

2.0 Middle🔥 114 комментариев
#Другое

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

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

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

Основные шаблоны проектирования в backend-разработке на C#

В backend-разработке я использую комбинацию классических шаблонов проектирования (GoF) и современных архитектурных паттернов, адаптированных под специфику серверных приложений. Вот ключевые категории и примеры их применения:

1. Архитектурные паттерны

Эти паттерны формируют структуру всего приложения.

Repository и Unit of Work — фундамент для работы с данными:

public interface IRepository<T> where T : class
{
    Task<T> GetByIdAsync(int id);
    Task AddAsync(T entity);
    Task UpdateAsync(T entity);
    Task DeleteAsync(T entity);
}

public class UnitOfWork : IUnitOfWork
{
    private readonly AppDbContext _context;
    
    public async Task CompleteAsync()
    {
        await _context.SaveChangesAsync();
    }
    
    // Паттерн Unit of Work объединяет несколько репозиториев
    // в одну транзакционную единицу
}

Dependency Injection (внедрение зависимостей) — основа современного C# backend:

public class UserService : IUserService
{
    private readonly IUserRepository _repository;
    private readonly ILogger<UserService> _logger;
    
    // Зависимости инжектятся через конструктор
    public UserService(IUserRepository repository, ILogger<UserService> logger)
    {
        _repository = repository;
        _logger = logger;
    }
}

2. Паттерны предметной области (Domain-Driven Design)

Aggregate Root — инкапсуляция бизнес-логики:

public class Order : AggregateRoot
{
    private readonly List<OrderItem> _items = new();
    
    public void AddItem(Product product, int quantity)
    {
        // Бизнес-правила валидации
        if (quantity <= 0)
            throw new BusinessException("Количество должно быть положительным");
            
        _items.Add(new OrderItem(product, quantity));
    }
    
    // Паттерн гарантирует целостность агрегата
}

Specification — для сложных критериев выборки:

public class ActiveUsersSpecification : Specification<User>
{
    public override Expression<Func<User, bool>> ToExpression()
    {
        return user => user.IsActive && 
                      user.LastLoginDate > DateTime.UtcNow.AddDays(-30);
    }
}

3. Паттерны для обработки запросов

CQRS (Command Query Responsibility Segregation) — разделение операций:

// Команда для изменения состояния
public class CreateUserCommand : IRequest<int>
{
    public string Email { get; set; }
    public string Name { get; set; }
}

// Запрос только для чтения
public class GetUserQuery : IRequest<UserDto>
{
    public int UserId { get; set; }
}

// Использование MediatR для обработки
public class CreateUserHandler : IRequestHandler<CreateUserCommand, int>
{
    public async Task<int> Handle(CreateUserCommand request, CancellationToken ct)
    {
        // Логика создания пользователя
    }
}

Mediator — посредник для уменьшения связности:

// Вместо прямых вызовов сервисов
public class UserController : ControllerBase
{
    private readonly IMediator _mediator;
    
    [HttpPost]
    public async Task<IActionResult> Create(CreateUserCommand command)
    {
        var result = await _mediator.Send(command);
        return Ok(result);
    }
}

4. Паттерны для повышения надежности

Circuit Breaker — защита от каскадных сбоев:

public class ResilientHttpClient
{
    private readonly CircuitBreakerPolicy _circuitBreaker;
    
    public ResilientHttpClient()
    {
        _circuitBreaker = Policy
            .Handle<HttpRequestException>()
            .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
    }
    
    public async Task<string> GetAsync(string url)
    {
        return await _circuitBreaker.ExecuteAsync(async () =>
        {
            // Выполнение HTTP-запроса
        });
    }
}

Retry и Fallback — стратегии обработки временных сбоев:

var policy = Policy
    .Handle<TimeoutException>()
    .WaitAndRetryAsync(3, retryAttempt => 
        TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)))
    .FallbackAsync(fallbackAction: async ct =>
    {
        // Альтернативная логика при постоянных сбоях
    });

5. Паттерны для производительности

Strategy — алгоритмы, выбираемые в runtime:

public interface IPaymentStrategy
{
    Task ProcessPaymentAsync(decimal amount);
}

public class CreditCardStrategy : IPaymentStrategy { }
public class PayPalStrategy : IPaymentStrategy { }
public class CryptoStrategy : IPaymentStrategy { }

// Контекст использует стратегию
public class PaymentProcessor
{
    private IPaymentStrategy _strategy;
    
    public void SetStrategy(IPaymentStrategy strategy)
    {
        _strategy = strategy;
    }
}

Decorator — динамическое добавление функциональности:

public class CachingUserRepositoryDecorator : IUserRepository
{
    private readonly IUserRepository _innerRepository;
    private readonly IMemoryCache _cache;
    
    public async Task<User> GetByIdAsync(int id)
    {
        return await _cache.GetOrCreateAsync($"user_{id}", async entry =>
        {
            entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5);
            return await _innerRepository.GetByIdAsync(id);
        });
    }
}

6. Паттерны для событийной архитектуры

Observer/Publisher-Subscriber — для loosely coupled систем:

public class DomainEventPublisher
{
    private readonly List<IDomainEventHandler> _handlers = new();
    
    public void Publish(DomainEvent @event)
    {
        foreach (var handler in _handlers)
        {
            handler.Handle(@event);
        }
    }
}

Процесс выбора паттернов всегда определяется конкретными требованиями:

  • Сложность бизнес-логики → DDD паттерны
  • Требования к производительности → CQRS, кэширование
  • Надежность и отказоустойчивость → Circuit Breaker, Retry
  • Гибкость и тестируемость → Dependency Injection, Repository

Ключевой принцип — не слепое следование паттернам, а их осмысленное применение для решения конкретных проблем: управления сложностью, повышения тестируемости, обеспечения масштабируемости и поддержки эволюции системы. В современных C# проектах особенно важно сочетать классические GoF-паттерны с архитектурными подходами типа Clean Architecture или Vertical Slice Architecture, которые определяют общую структуру приложения.

Какие шаблоны проектирования используешь для backend? | PrepBro