Open Close Principle (OCP)
Zasada otwarte/zamknięte jest drugą z pięciu podstawowych zasad programowania obiektowego ukrytych pod akronimem SOLID. OCP czyli Open Close Principle mówi o tym, że klasy, moduły czy funkcje powinny być otwarte na rozszerzenia, ale zamknięte na modyfikacje. Oznacza to, że powinniśmy pisać programy w taki sposób, aby można było dopisywać kolejne funkcjonalności bez ingerowania w już napisany kod. Dzięki tej zasadzie kod jest o wiele łatwiejszy w rozbudowie oraz ze względu na brak modyfikacji istniejącego kodu możemy czuć się bezpiecznie, że pojawią się błędy tam gdzie ich wcześniej nie było.
Przykład kodu bez zastosowania OCP:
public class KontoOszczednosciowe {
public decimal obliczOdsetki(TypKonta typKonta) {
if (TypKonta == “Zwykle”) {
//oblicz odsetki dla konta zwykłego na podstawie zasad i regulacji banku
if(saldo < 1000) odsetki = saldo * 0.0017; //2% w skali roku
if(saldo < 50000) odsetki = saldo * 0.0029; //3.5% w skali roku
if(saldo >= 50000) odsetki = saldo * 0.0042; //5% w skali roku
}
else if (TypKonta == “Wynagrodzenie”) {
//oblicz odsetki dla konta oszczędnościowego na podstawie zasad i regulacji banku
odsetki = wynagrodzenie * 0.01;
}
}
}
W powyższym kodzie metoda obliczOdsetki klasy KontoOszczednosciowe dokonuje obliczeń odsetek w zależności od typu konta.
Przyjmijmy teraz, że bank chciałby dodać nowy typ konta oszczędnościowego np. konto oszczędnościowe dla dzieci. Chcąc to uczynić należy zmodyfikować metodę “obliczOdsetki” dodając kolejny warunek if dla nowego typu konta. Taka zmiana jest niezgodna z OCP.
Aby zaimplementować zasadę Open/Close można użyć np. interfejsu czy klasy abstrakcyjnej, a następnie dziedziczyć je, gdy chcemy rozszerzyć funkcjonalność.
Przykładowy kod zgodny z zasadą OCP:
public interface IKontoOszczednosciowe {
decimal obliczOdsetki();
}
public class ZwykleKontoOszczednosciowe implements IKontoOszczednosciowe {
@Override
public decimal obliczOdsetki() {
//oblicz odsetki dla konta zwykłego na podstawie zasad i regulacji banku
if(saldo < 1000) odsetki = saldo * 0.0017; //2% w skali roku
if(saldo < 50000) odsetki = saldo * 0.0029; //3.5% w skali roku
if(saldo >= 50000) odsetki = saldo * 0.0042; //5% w skali roku
}
}
public class WynagrodzenieKontoOszczednosciowe implements IKontoOszczednosciowe {
@Override
public decimal obliczOdsetki() {
//oblicz odsetki dla konta oszczędnościowego na podstawie zasad i regulacji banku
odsetki = wynagrodzenie * 0.01;
}
}
W tym przykładzie utworzone zostały dwie klasy reprezentujące typ konta oszczędnościowego: ZwykleKontoOszczednosciowe i WynagrodzenieKontoOszczednosciowe. Obie te klasy dziedziczą po interfejsie IKontoOszczednosciowe i nadpisują metodę obliczOdsetki().
Jeśli teraz bank zdecyduje się dodać nowy typ konta oszczędnościowego to wystarczy, że utworzy nową klasę reprezentującą nowy typ konta, odziedziczy po interfejsie i nadpisze metodę.
W ten sposób mamy spełnioną zasadę OCP ponieważ nie ma potrzeby modyfikowania już istniejącego kodu i jednocześnie jest możliwość rozszerzenia w celu dodania nowej logiki.