Что такое связность (cohesion) в разработке ПО?

«Что такое связность (cohesion) в разработке ПО?» — вопрос из категории Архитектура, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Связность (cohesion) — это метрика, оценивающая, насколько тесно связаны между собой обязанности и функциональность внутри одного модуля (класса, метода, компонента). Высокая связность — один из ключевых принципов хорошего проектирования (наряду со слабой связанностью).

Принцип: Элементы внутри модуля должны быть объединены выполнением одной, четко определённой задачи или ответственности.

Почему высокая связность — это хорошо?

  • Упрощает понимание: Класс с одной ответственностью легче понять и изучить.
  • Упрощает поддержку: Изменения в одной функциональной области затрагивают только один модуль.
  • Повышает переиспользуемость: Чётко выделенный функционал проще использовать в других контекстах.
  • Упрощает тестирование: Легче написать сфокусированные модульные тесты.

Примеры:

1. Класс с высокой связностью (функциональная связность):

// Этот класс отвечает только за валидацию email-адресов.
// Все его методы тесно связаны с одной задачей.
public class EmailValidator
{
    public bool IsValidFormat(string email) 
    { 
        return Regex.IsMatch(email, @"^[^@s]+@[^@s]+.[^@s]+$"); 
    }

    public bool IsDomainAllowed(string email, HashSet<string> allowedDomains)
    {
        var domain = email.Split('@').Last();
        return allowedDomains.Contains(domain);
    }

    public ValidationResult Validate(string email, HashSet<string> allowedDomains)
    {
        if (!IsValidFormat(email)) 
            return ValidationResult.Fail("Invalid format");
        if (!IsDomainAllowed(email, allowedDomains)) 
            return ValidationResult.Fail("Domain not allowed");
        return ValidationResult.Success();
    }
}

2. Класс с низкой связностью (случайная/логическая связность):

// Этот класс объединяет три несвязанные ответственности.
// Изменение правил логирования не должно касаться класса, работающего с заказами.
public class OrderManager // Плохое название для такого набора методов
{
    public void ProcessOrder(Order order) { /* ... */ }
    public void SendPromotionalEmail(Customer customer) { /* ... */ } // Отвечает за коммуникацию
    public void LogErrorToDatabase(Exception ex) { /* ... */ }       // Отвечает за инфраструктуру логирования
}

Рефакторинг: Класс с низкой связностью следует разделить на несколько классов, каждый со своей высокой связностью: OrderProcessor, EmailService, Logger.