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!");
}
}

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();
}
}
Kiedy zasada jest ważna?
- W dużych projektach z wieloma typami obiektów o różnych rolach,
- Gdy interfejsy zaczynają być zbyt „ciężkie” (zawierają za dużo metod).
Na co zwracać uwagę:
- Lepiej mieć kilka małych interfejsów niż jeden ogromny,
- Klasy powinny implementować tylko to, co jest im naprawdę potrzebne.
Trudności:
- Początkujący często tworzą zbyt dużo drobnych interfejsów, przez co projekt staje się nadmiernie skomplikowany,
- Trzeba znaleźć balans między szczegółowością a praktycznością.
