SOLID jest to zestaw zasad dobrego programowania obiektowego. Stanowią fundament projektowania oprogramowania które mogą pomóc programistom tworzyć bardziej zorganizowane, elastyczne i łatwe w utrzymaniu systemy.
Czwarta zasada SOLID jest to zasada segregacji interfejsów (ang. interface segregation principle) sformułowana przez Roberta C. Martin.
Jaka jest Definicja ?
Zgodnie z zasadą segregacji interfejsów, żadna klasa nie powinna być zmuszona do implementacji interfejsów, których metody nie są związane z jej funkcjonalnością i nie są używane. W związku z tym, interfejsy powinny być tak zaprojektowane aby były konkretne, jak najmniejsze i dostosowane do funkcjonalności poszczególnych klas.
Jak to osiągnąć?
Zamiast tworzyć jeden ogólny interfejs „do wszystkich klas”, lepszym rozwiązaniem jest zdefiniowanie większej liczby małych interfejsów związanych z konkretnym zadaniem.
Poniżej zaprezentowany przykład jest błędny, ponieważ nie każda metoda definiowana przez interfejs jest wykorzystywana w klasach pochodnych. W obecnym przykładzie klasy Latte i Americano implementują interfejs IKawa, który zawiera metody których nie potrzebują do prawidłowego działania i spełnienia funkcji.
public interface IKawa {
void dodajEspresso();
void dodajWodę();
void dodajSpienioneMleko();
void dodajMlecznaPianka();
}
public class Americano implements IKawa {
@Override
public void dodajEspresso() {
System.out.println("Espresso");
}
@Override
public void dodajWodę() {
System.out.println("Dodaj wodę");
}
@Override
public void dodajSpienioneMleko() {
throw new RuntimeException();
}
@Override
public void dodajMlecznaPianka() {
throw new RuntimeException();
}
}
public class Latte implements IKawa {
@Override
public void dodajEspresso() {
System.out.println("Espresso");
}
@Override
public void dodajWodę() {
throw new RuntimeException();
}
@Override
public void dodajSpienioneMleko() {
System.out.println("Spienione mleko");
}
@Override
public void dodajMlecznaPianka() {
System.out.println("Mleczna pianka");
}
}
W kolejnym przykładzie unikniemy tego problemu, tworząc bardziej specyficzne, konkretne interfejsy – IEspresso, IWoda, ISpienioneMleko oraz IMlecznaPianka. Natomiast każda z klas będzie mogła zaimplementować tylko te interfejsy, które są zgodne z ich funkcjonalnością.
public interface IEspresso {
void dodajEspresso();
}
public interface IWoda {
void dodajWodę();
}
public interface ISpienioneMleko {
void dodajSpienioneMleko();
}
public interface IMlecznaPianka {
void dodajMlecznaPianka();
}
public class Latte implements IEspresso, ISpienioneMleko, IMlecznaPianka {
@Override
public void dodajEspresso() {
System.out.println("Espresso");
}
@Override
public void dodajSpienioneMleko() {
System.out.println("Spienione mleko");
}
@Override
public void dodajMlecznaPianka() {
System.out.println("Mleczna pianka");
}
}
public class Americano implements IEspresso, IWoda {
@Override
public void dodajEspresso() {
System.out.println("Espresso");
}
@Override
public void dodajWodę() {
System.out.println("Dodaj wodę");
}
}