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

Какой подход реализовал в созданном классе?

2.0 Middle🔥 191 комментариев
#Основы C# и .NET

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

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

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

Подходы к проектированию классов в C#

При создании класса в C# я реализую комбинацию современных принципов объектно-ориентированного проектирования (ООП) и архитектурных паттернов, адаптированных под конкретные требования проекта. Вот ключевые подходы, которые я применяю:

1. Принципы SOLID как фундамент

SOLID — это основа, на которой строится любой мой класс:

// Пример класса, реализующего SRP и OCP
public class OrderProcessor : IOrderProcessor
{
    private readonly IOrderValidator _validator;
    private readonly IOrderRepository _repository;
    private readonly INotificationService _notificationService;
    
    // Dependency Injection для соблюдения DIP
    public OrderProcessor(
        IOrderValidator validator,
        IOrderRepository repository, 
        INotificationService notificationService)
    {
        _validator = validator;
        _repository = repository;
        _notificationService = notificationService;
    }
    
    // Единственная ответственность (SRP) — обработка заказа
    public async Task<OrderResult> ProcessOrderAsync(Order order)
    {
        // Валидация через абстракцию (DIP)
        if (!await _validator.ValidateAsync(order))
            return OrderResult.ValidationFailed();
        
        // Открытость для расширения (OCP)
        var processedOrder = await ApplyBusinessRules(order);
        
        await _repository.SaveAsync(processedOrder);
        await _notificationService.NotifyOrderCreated(processedOrder);
        
        return OrderResult.Success(processedOrder);
    }
    
    // Приватные методы для инкапсуляции логики
    private async Task<Order> ApplyBusinessRules(Order order)
    {
        // Логика может быть расширена без изменения класса
        return order;
    }
}

2. Domain-Driven Design (DDD) для сложных доменов

Для бизнес-логики я применяю DDD подход:

// Богатая модель с инкапсуляцией бизнес-правил
public class ShoppingCart : Entity<Guid>
{
    private readonly List<CartItem> _items = new();
    private Money _totalAmount = Money.Zero;
    
    public IReadOnlyCollection<CartItem> Items => _items.AsReadOnly();
    public CustomerId CustomerId { get; private set; }
    public DateTime CreatedAt { get; private set; }
    
    // Инварианты защищены внутри класса
    public void AddItem(Product product, int quantity)
    {
        if (quantity <= 0)
            throw new DomainException("Quantity must be positive");
            
        var existingItem = _items.FirstOrDefault(i => i.ProductId == product.Id);
        
        if (existingItem != null)
        {
            existingItem.IncreaseQuantity(quantity);
        }
        else
        {
            _items.Add(new CartItem(product, quantity));
        }
        
        RecalculateTotal();
    }
    
    private void RecalculateTotal()
    {
        _totalAmount = _items.Sum(item => item.TotalPrice);
    }
    
    // Явное выражение намерений через методы
    public Order Checkout(PaymentMethod paymentMethod)
    {
        if (!_items.Any())
            throw new DomainException("Cannot checkout empty cart");
            
        var order = Order.CreateFromCart(this, paymentMethod);
        Clear(); // Состояние изменяется предсказуемо
        
        return order;
    }
}

3. Паттерны проектирования для решения конкретных задач

Я выбираю паттерны исходя из контекста:

  • Стратегия (Strategy) для алгоритмов
  • Фабрика (Factory) для создания сложных объектов
  • Спецификация (Specification) для фильтрации
  • Декоратор (Decorator) для добавления поведения
// Пример использования нескольких паттернов
public class DiscountCalculator
{
    private readonly List<IDiscountStrategy> _strategies;
    
    public DiscountCalculator(IEnumerable<IDiscountStrategy> strategies)
    {
        _strategies = strategies.OrderBy(s => s.Priority).ToList();
    }
    
    public Money CalculateDiscount(Order order)
    {
        // Цепочка ответственности + Стратегия
        return _strategies
            .Select(strategy => strategy.CalculateDiscount(order))
            .FirstOrDefault(discount => discount > Money.Zero);
    }
}

// Спецификация для фильтрации
public class ActiveOrdersSpecification : Specification<Order>
{
    public override Expression<Func<Order, bool>> ToExpression()
    {
        return order => order.Status == OrderStatus.Processing 
                     && order.CreatedAt >= DateTime.UtcNow.AddDays(-7);
    }
}

4. Асинхронность и потокобезопасность

Для высоконагруженных backend-систем критически важны:

public class RateLimitedService
{
    private readonly SemaphoreSlim _semaphore = new(10, 10);
    private readonly ConcurrentDictionary<string, DateTime> _lastCall = new();
    
    public async Task<ApiResponse> CallWithRateLimitAsync(string endpoint)
    {
        await _semaphore.WaitAsync();
        
        try
        {
            // Проверка временных ограничений
            if (_lastCall.TryGetValue(endpoint, out var lastCallTime))
            {
                var timeSinceLastCall = DateTime.UtcNow - lastCallTime;
                if (timeSinceLastCall < TimeSpan.FromSeconds(1))
                {
                    await Task.Delay(1000 - timeSinceLastCall.Milliseconds);
                }
            }
            
            var response = await MakeApiCallAsync(endpoint);
            _lastCall[endpoint] = DateTime.UtcNow;
            
            return response;
        }
        finally
        {
            _semaphore.Release();
        }
    }
}

5. Тестируемость как критерий качества

Класс проектируется с учетом тестирования:

// Класс легко тестируется благодаря зависимостям через интерфейсы
public class PaymentService : IPaymentService
{
    private readonly IPaymentGateway _gateway;
    private readonly ILogger<PaymentService> _logger;
    
    public PaymentService(
        IPaymentGateway gateway,
        ILogger<PaymentService> logger)
    {
        _gateway = gateway;
        _logger = logger;
    }
    
    // Методы чистые и предсказуемые
    public async Task<PaymentResult> ProcessPaymentAsync(PaymentRequest request)
    {
        try
        {
            // Логика изолирована от внешних зависимостей
            var validationResult = ValidateRequest(request);
            if (!validationResult.IsValid)
                return PaymentResult.Failed(validationResult.Errors);
            
            var paymentResponse = await _gateway.ChargeAsync(request);
            
            return MapToResult(paymentResponse);
        }
        catch (PaymentGatewayException ex)
        {
            _logger.LogError(ex, "Payment processing failed");
            return PaymentResult.Failed("Gateway error");
        }
    }
}

Ключевые принципы моего подхода:

  1. Инкапсуляция бизнес-правил внутри доменных объектов
  2. Явные контракты через интерфейсы
  3. Неизменяемость (immutability) где это возможно
  4. Принцип наименьшего удивления — класс ведет себя предсказуемо
  5. Ленивая инициализация для ресурсоемких операций
  6. Правильная обработка ошибок и исключительных ситуаций
  7. Логирование ключевых действий для диагностики
  8. Поддержка асинхронности на всех уровнях

Такой подход позволяет создавать масштабируемые, поддерживаемые и тестируемые классы, которые интегрируются в общую архитектуру приложения без tight coupling. Каждый класс имеет четкую зону ответственности и взаимодействует с другими компонентами через хорошо определенные интерфейсы, что соответствует современным стандартам разработки enterprise-приложений на C#.