Что такое связанность (coupling) в коде?

Ответ

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

Уровни связанности (от лучшего к худшему):

  1. Data coupling (связь по данным): Модули общаются только через передачу простых параметров.
  2. Stamp coupling (связь по структуре): Модули передают составные структуры данных (например, объекты), но используют только их часть.
  3. Control coupling (связь по управлению): Один модуль передает другому флаг или данные, явно управляющие его логикой.
  4. Common coupling (общая связь): Модули используют общие глобальные данные.
  5. Content coupling (содержательная связь): Один модуль напрямую изменяет внутренние данные или логику другого (например, через goto или изменение приватных полей).

Пример слабой связанности (предпочтительный):

// Модуль OrderProcessor зависит только от абстракции PaymentGateway.
class OrderProcessor {
    private PaymentGateway $paymentGateway;

    public function __construct(PaymentGateway $gateway) {
        $this->paymentGateway = $gateway; // Внедрение зависимости
    }

    public function process(Order $order): void {
        $this->paymentGateway->charge($order->getAmount());
    }
}

Пример сильной связанности (проблемный):

// OrderProcessor жестко зависит от конкретного класса PayPal и способа получения данных.
class OrderProcessor {
    public function process(int $orderId): void {
        $payment = new PayPal(); // Прямое создание зависимости
        $order = Order::find($orderId); // Статический вызов, привязка к глобальному состоянию
        $payment->charge($order->amount);
    }
}

Почему важна слабая связанность: Она повышает тестируемость (легко подменить зависимости заглушками), переиспользуемость и упрощает рефакторинг системы.

Ответ 18+ 🔞

Давай разберем, что такое связанность, без этих заумных учебников. Представь, что твой код — это общага. Связанность — это мера того, насколько твои соседи по блоку в курсе твоих личных дел и лезут в твой холодильник. Высокая связанность — это пиздец, бардак и скандалы на районе: чуть что поменял в своей жизни, а у половины этажа истерика начинается.

Уровни этой самой связанности, от нормы до полного пиздеца:

  1. Связь по данным (Data coupling). Идеал, мечта. Как с соседом-адекватом: «Друг, передай, пожалуйста, соль». Ты передал соль, он тебе спасибо. Всё. Никто никому не должен, в душу не лезет. В коде это когда модули тупо простые данные друг другу кидают.
  2. Связь по структуре (Stamp coupling). Уже хуже. Это как ты не просто соль передаёшь, а целую полку из своего шкафа со всеми банками, норами пауков и завалявшимся носком. Сосед берёт только соль, но вынужден принимать весь этот хлам. Модуль получает здоровенную структуру (объект), а юзает из неё одно поле. Подозрение ёбать чувствую к такому.
  3. Связь по управлению (Control coupling). Вот тут начинается цирк. Ты не просто данные передаёшь, а командуешь: «На, держи флажок. Если он красный — пой песни, если синий — пляши». Один модуль начинает вертеть другим, как хочет. Логика расползается, доверия ёбать ноль.
  4. Общая связь (Common coupling). А это уже настоящий ад, ёпта. Все модули лезут в один общий, глобальный холодильник. Один сожрал колбасу, другой пописал в молоко. Кто что сделал — хрен поймёшь. Изменение одной переменной где-то в углу ломает всё приложение. Терпения ноль ёбать отлаживать эту хуйню.
  5. Содержательная связь (Content coupling). Абсолютный пик идиотизма, пиздопроебибна архитектура. Это когда один модуль лезет прямо в кишки другого, меняет его приватные поля или прыгает внутрь его функций через goto. Это как сосед не просто взял твою соль, а вломился к тебе в комнату, пока ты спишь, и сам её набрал. После такого хочется вилкой в глаз.

Пример, как надо делать (слабая связь, красота):

class OrderProcessor {
    private PaymentGateway $paymentGateway;

    public function __construct(PaymentGateway $gateway) {
        $this->paymentGateway = $gateway; // Подсунули нужный шлюз снаружи
    }

    public function process(Order $order): void {
        $this->paymentGateway->charge($order->getAmount()); // Работает с абстракцией
    }
}

Вот это — красота. OrderProcessor не парится, кто именно платит — PayPal, Stripe или картой почтальона Печкина. Ему подсунули интерфейс, он с ним и работает. Тестировать — одно удовольствие, можно заглушку подставить.

А вот пример говнокода (сильная связь, полный распиздяй):

class OrderProcessor {
    public function process(int $orderId): void {
        $payment = new PayPal(); // Жёстко прибит гвоздями к PayPal! Хуй с горы!
        $order = Order::find($orderId); // Лезет в глобальное состояние, как в чужой холодильник
        $payment->charge($order->amount);
    }
}

Ядрёна вошь! Смотри, что тут творится:

  1. Создаёт конкретный PayPal внутри себя. Захотим поменять на карту — придётся весь этот класс перелопачивать.
  2. Лезут в базу через статический метод Order::find(). Это та самая общая связь, зависимость от глобального состояния. Протестировать такое в изоляции? Да похуй, невозможно.

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