Przedostatnia zasada mnemoniku SOLID. Według tej wytycznej interfejsy należy odpowiednio segregować. Nie jest zalecane tworzenie interfejsu “od wszystkiego”. Powinno się je konstruować w taki sposób, aby miały tylko jedną odpowiedzialność (Single Responsible Principle). Klas implementujących dany interfejs nie należy zmuszać do implementowania funkcjonalności, których nie potrzebują. Naruszono by w ten sposób zasadę Barbary Liskov (Liskov Substitution Principle). Można więc powiedzieć, że jest to reguła korzystająca z dobrodziejstw dwóch innych wytycznych.
Należy dzielić duże interfejsy na mniejsze
Można powiedzieć, że interfejs jest kontraktem zawieranym pomiędzy wywołującym a klasą. Jeśli będzie on zbyt długi to łatwo się w nim pogubić (tak jak w prawdziwym życiu). Z tego powodu reguła Interface segregation principle zaleca, aby takie kontrakty zmniejszać, aby miały tylko jedną odpowiedzialność. W ten sposób uzyskujemy luźne powiązania pomiędzy poszczególnymi elementami, a co za tym idzie uzyskujemy łatwość testowania, refaktoringu oraz utrzymania kodu. Przejdźmy zatem do przykładu łamiącego zasadę Segregacji Interfejsów:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public interface Tasks {
void organizeMeetings();
void motivateTeam();
}
public class OrganizationManager implements Tasks {
public void organizeMeetings() {
// organize meetings
}
public void motivateTeam() {
throw new TypeOfWorkNotSupportedException();
}
}
public class MotivationManager implements Tasks {
public void organizeMeetings() {
throw new TypeOfWorkNotSupportedException();
}
public void motivateTeam() {
// motivate team
}
}
Załóżmy sytuację, w której wiele innych projektów korzysta z tego interfejsu w podobny sposób. Klasy go implementujące tak naprawdę potrzebują tylko jedną metodę z dwóch dostępnych. Przypuśćmy, że nagle przychodzi wymaganie, które karze nam zrobić zmianę w tym konkretnym interfejsie. W rezultacie w każdym projekcie trzeba obsłużyć to nowe ulepszenie co wiąże się z wieloma zmianami. Z tego powodu zasada Segregacji Interfejsów ma sens, ponieważ znacznie ułatwia nam pracę.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public interface OrganizationTasks {
void organizeMeetings();
}
public interface MotivationTasks {
void motivateTeam();
}
public class OrganizationManager implements OrganizationTasks {
public void organizeMeetings() {
// organize meetings
}
}
public class MotivationManager implements MotivationTasks {
public void motivateTeam() {
// motivate team
}
}
W ten sposób unikniemy niepotrzebnych zmian we wszystkich projektach. Dodatkowo atutem jest to, że zadania są odpowiednio posegregowane. Kod jest łatwiejszy do zarządzania i utrzymania.
Podsumowanie
Według mnie zasada Segregacji Interfejsów jest zwieńczeniem dwóch innych reguł. Trzymanie się jej pozwala nam nie tworzyć klas “od wszystkiego”. Jak wszystko, tak i Interface segregation principle nie uchroni nas przed całym złem. Jednak moim zdaniem warto brać ją pod uwagę podczas pisania kodu źródłowego. Z pewnością nasze klasy będą czytelniejsze i łatwiejsze w utrzymaniu. Warto więc się zastanowić czy dobrze rozumiem tę regułę i wiem jak poprawnie ją stosować.
Jak zawsze będę wdzięczny za to, że przekażesz mi swoją opinię na poruszony wyżej temat. Z chęcią zapoznam się również z jakimiś innymi przypadkami łamania zasady Segregacji Interfejsów i próbą ich naprawienia. Zachęcam Cię do wyrażenia swojego zdania w komentarzu bądź wysłania go do mnie bezpośrednio na maila!