Zasada Segregacji Interfejsów



Definicja

Zasada segregacji interfejsów (ang. Interface Segregation Principle, ISP) mówi, że
żaden klient nie powinien być zmuszany do implementowania metod, których nie używa.

W praktyce oznacza to, że duże interfejsy należy rozdzielać na mniejsze, bardziej wyspecjalizowane, tak aby klasy implementowały tylko to, co rzeczywiście jest im potrzebne.
To sprawia, że kod jest bardziej elastyczny, łatwiejszy w utrzymaniu i mniej podatny na błędy.

Przykład z życia

Wyobraźmy sobie fabrykę prefabrykatów żelbetowych.
Mamy różne typy maszyn:

  • maszyna zbrojeniowa (wykonuje i montuje zbrojenie),
  • maszyna zalewająca betonem,
  • maszyna transportowa (przenosi elementy).

Jeśli stworzymy jeden wspólny interfejs Machine z metodami assembleReinforcement(), pourConcrete(), transportElement(),
to każda maszyna będzie musiała implementować wszystkie te metody – nawet te, których nie potrzebuje.

Lepiej więc rozdzielić interfejsy: osobno dla zbrojenia, zalewania i transportu.

Przykłady przed i po zastosowaniu zasady

PRZED

Klasa ReinforcementMachine jest zmuszona implementować metody, które nie mają sensu w jej kontekście.
To narusza zasadę segregacji interfejsów i prowadzi do błędów w czasie działania programu.

interface Machine {
    void assembleReinforcement();
    void pourConcrete();
    void transportElement();
}


class ReinforcementMachine implements Machine {
    @Override
    public void assembleReinforcement() {
        System.out.println("Assembling reinforcement for prefab element...");
    }



    @Override
    public void pourConcrete() {
        // Ta maszyna nie wykonuje tego zadania!
        throw new UnsupportedOperationException("Reinforcement machine cannot pour concrete!");
    }



    @Override
    public void transportElement() {
        // I tego też nie robi
        throw new UnsupportedOperationException("Reinforcement machine cannot transport elements!");
    }
}
Designed by Freepik

PO

Zastosujmy zasadę ISP i podzielmy interfejs Machine na mniejsze, bardziej wyspecjalizowane interfejsy

Dlaczego teraz działa lepiej:

  • Dodanie nowego typu maszyny (np. maszyny szlifującej) wymaga jedynie nowego interfejsu i klasy — bez modyfikowania istniejących.
  • Każda maszyna implementuje tylko te metody, które rzeczywiście wykonuje.
// Interfejs dla maszyn wykonujących zbrojenie
interface ReinforcementWorker {
    void assembleReinforcement();
}

// Interfejs dla maszyn zalewających betonem
interface ConcreteWorker {
    void pourConcrete();
}

// Interfejs dla maszyn transportowych
interface TransportWorker {
    void transportElement();
}

// Klasa implementująca tylko to, co potrzebne
class ReinforcementMachine implements ReinforcementWorker {
    @Override
    public void assembleReinforcement() {
        System.out.println("Assembling reinforcement for prefab element...");
    }
}

class ConcreteMachine implements ConcreteWorker {
    @Override
    public void pourConcrete() {
        System.out.println("Pouring concrete into mold...");
    }
}

class TransportMachine implements TransportWorker {
    @Override
    public void transportElement() {
        System.out.println("Transporting prefab element to curing area...");
    }
}

// Klasa główna – przykład użycia
public class Main {
    public static void main(String[] args) {
        ReinforcementWorker rebar = new ReinforcementMachine();
        ConcreteWorker concrete = new ConcreteMachine();
        TransportWorker transport = new TransportMachine();

        rebar.assembleReinforcement();
        concrete.pourConcrete();
        transport.transportElement();
    }
}