Druga zasada mnemoniku SOLID. Praktyka mówiąca, że klasy powinny być otwarte na rozszerzenia, ale zamknięte na modyfikacje. Opracował ją Bertrand Meyer w 1988 r. Według niej dana encja powinna mieć możliwość zmiany swojego zachowania bez ingerowania w kod źródłowy. W ten sposób wytwarzamy system, który potrafi dostosować się do zmiennych wymagań.
Klasa zamyka się na modyfikacje, ale zawsze powinna być otwarta na rozszerzenie.
Tą zasadę można zilustrować następująco:
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
public class Manager {
private Task task;
public Manager(task) {
this.task = task;
}
public void work() {
switch(task) {
case ORGANIZE_MEETINGS:
organizeMeetings();
break;
case MOTIVATE_TEAM:
motivateTeam();
break;
default:
haveDayOff();
}
}
}
public enum Task {
ORGANIZE_MEETINGS, MOTIVATE_TEAM
}
Przy tworzeniu obiektu Manager przekazujemy parametr odpowiadający pracy jaką ma dzisiaj do wykonania. W przypadku, gdyby doszedł nowy typ zadania niezbędna byłaby ingerencja w kod źródłowy. Z tego powodu należałoby w instrukcji switch obsłużyć nowy rodzaj pracy. Jest to uciążliwe dla programisty i zdecydowanie łamie zasadę Otwarte-Zamknięte. Rozwiązaniem tego zagadnienia jest przechowywanie wspólnego, niezmiennego zachowania w abstrakcji (klasie abstrakcyjnej albo interfejsie). W efekcie odmienne części kodu źródłowego należy zamieścić w klasach konkretnych rozszerzających daną abstrakcję.
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
27
28
29
30
31
public class Manager {
private Task task;
public Manager(task) {
this.task = task;
}
public void work() {
task.getTheJobDone();
}
}
public interface Task {
void getTheJobDone();
}
public class OrganizeMeetingsTask implements Task {
@Override
public void getTheJobDone() {
// do task - organize meetings
}
}
public class MotivateTeamTask implements Task {
@Override
public void getTheJobDone() {
// do task - motivate team
}
}
Taki sposób zapisu jest o wiele przyjemniejszy w utrzymaniu. Dzięki czemu dodając nowe typy zadań nie istnieje potrzeba zmiany implementacji klasy Manager. W rezultacie nasz kod źródłowy na pewno jest otwarty na rozszerzenia i zamknięty na modyfikacje 👍.
Podsumowanie
Osobiście uważam, że zasada Open/Closed Principle jest bardzo przydatna. Dzięki niej nasz kod jest mniej ze sobą powiązany i nie uzyskujemy zależności pomiędzy elementami. Trzymanie się tej reguły naprowadza nas na bardzo przydatny wzorzec architektoniczny jakim jest Strategia. Zachęcam do dyskusji na temat zasady Otwarte-Zamknięte poprzez napisanie komentarza pod postem lub wysłanie do mnie maila. Czy posiada ona same zalety, a może jednak ma jakieś wady, które nie przemawiają za nią? Może jesteś w stanie lepiej zilustrować tą regułę? Z chęcią się zapoznam z Twoim punktem widzenia!