EA - Coupling i Kohezja

Każdy programista słyszał o zasadach dobrego kodu: czytelność, modularność, łatwość testowania, niskie koszty utrzymania. Ale jak je osiągnąć?



Jednym z fundamentów są dwa niepozorne, lecz kluczowe pojęcia: kohezja (cohesion) i sprzężenie (coupling).

W tym artykule wyjaśnię, czym są, jak wpływają na jakość systemu i pokażę praktyczne przykłady.

Coupling (sprzężenie)

Sprzężenie to miara zależności między modułami/kontrolerami/klasami.

  • Niskie sprzężenie (loose coupling) – moduły są niezależne, zmiana jednego nie powoduje efektu domina.

  • Wysokie sprzężenie (tight coupling) – zmiana w jednym komponencie wymusza zmiany w wielu innych, co utrudnia rozwój i testowanie.

Przykład wysokiego sprzężenia:


class OrderService { private final EmailService emailService = new EmailService(); public void placeOrder(Order order) { // logika zamówienia emailService.sendConfirmation(order.getUserEmail()); } }

OrderService tworzy instancję EmailService i staje się od niej zależny. Nie można tego łatwo przetestować, wymienić implementacji, ani odseparować.

Przykład niskiego sprzężenia (dobrze):


class OrderService { private final EmailService emailService; public OrderService(EmailService emailService) { this.emailService = emailService; } public void placeOrder(Order order) { // logika zamówienia emailService.sendConfirmation(order.getUserEmail()); } }

Tu zastosowano wstrzykiwanie zależności (Dependency Injection). OrderService nie obchodzi, jaka to implementacja EmailService. Dzięki temu łatwiej pisać testy, refaktoryzować i utrzymywać kod.

Cohesion (kohezja, spójność)

Kohezja to miara jak bardzo odpowiedzialności danego modułu są ze sobą powiązane.

  • Wysoka kohezja – klasa/metoda ma jedno konkretne zadanie.

  • Niska kohezja – klasa robi wszystko: zapisuje dane, wysyła e-maile, liczy podatki i jeszcze zapisuje logi...

Przykład niskiej kohezji:


class ReportManager { public void generateReport() { /* ... */ } public void sendReportByEmail() { /* ... */ } public void logReportToFile() { /* ... */ } public void calculateRevenue() { /* ... */ } }

Ta klasa ma wiele odpowiedzialności. Trudno ją rozszerzyć lub przetestować.

Przykład wysokiej kohezji (dobrze):


class ReportGenerator { public Report generate() { /* ... */ } } class ReportSender { public void send(Report report) { /* ... */ } } class RevenueCalculator { public BigDecimal calculate(Report report) { /* ... */ } }

Każda klasa ma jedno zadanie (Single Responsibility Principle) i dobrze współpracuje z innymi – ale nie jest z nimi nadmiernie powiązana. To przykład wysokiej kohezji i niskiego sprzężenia – złotego standardu projektowania.

Dlaczego to ważne?

Cecha systemuNiskie sprzężenieWysoka kohezja
Testowalność✅ Łatwa✅ Łatwa
Rozszerzalność✅ Modułowa✅ Przewidywalna
Refaktoryzacja✅ Bezpieczna✅ Czysta
Zrozumiałość kodu✅ Izolowana✅ Logiczna

Jak to osiągnąć?

✅ Stosuj wstrzykiwanie zależności
✅ Dziel kod zgodnie z zasadą jednej odpowiedzialności (SRP)
✅ Używaj wzorców projektowych (np. Strategy, Adapter)
✅ Grupuj klasy zgodnie z kontekstem domeny (np. DDD)
✅ Refaktoruj, gdy widzisz "kuchnię z tysiącem zadań"

Podsumowanie

  • Coupling to pytanie: jak bardzo zależysz od innych?

  • Cohesion to pytanie: czy robisz jedną rzecz dobrze, czy wszystko po trochu?

Dążymy do niskiego sprzężenia i wysokiej kohezji – to podstawa dobrze zaprojektowanych, testowalnych i skalowalnych systemów.

Komentarze