Open/Closed Principle

Open/Closed Principle – OCP

Klasy, moduły lub funkcje powinny być otwarte na rozbudowę, ale zamknięte na modyfikacje. Oznacza to, że powinniśmy być w stanie dodawać nową funkcjonalność bez konieczności zmieniania istniejącego kodu

Korzyści z zastosowania zasady OCP:

Zmniejszenie ryzyka błędów: Unikamy wprowadzania zmian do istniejącego kodu, co zmniejsza ryzyko wprowadzenia błędów.

Łatwiejsze dodawanie nowych funkcji: Dzięki tej zasadzie, dodawanie nowych funkcjonalności (np. nowych kształtów) jest łatwiejsze i bezpieczniejsze

Lepsza architektura: Kiedy nasz kod przestrzega zasady OCP, staje się bardziej modularny i elastyczny.

Przykład z życia codziennego:

Menu w restauracji

Wyobraź sobie restaurację, która ma swoje standardowe menu. Menu zawiera dania, takie jak przystawki, dania główne i desery. Restauracja działa przez kilka lat, oferując te same pozycje w menu.

Scenariusz łamiący zasadę OCP

Właściciel restauracji zauważa, że klienci coraz częściej pytają o nowe dania, takie jak wegańskie przystawki czy dania bezglutenowe. Aby dodać te nowe opcje do menu, właściciel postanawia ręcznie zaktualizować każdą stronę menu, zmieniając istniejące pozycje i dodając nowe.

  • Problem: Za każdym razem, gdy właściciel chce dodać nową pozycję do menu, musi ręcznie edytować całe menu. Jeśli później zdecyduje się na kolejne zmiany, znowu musi przejść przez cały proces edycji. To zajmuje dużo czasu i jest podatne na błędy, np. pominięcie jakiejś kategorii lub błędne wpisanie ceny.

Przykład stosujący zasadę OCP

Zamiast ręcznie edytować menu za każdym razem, właściciel restauracji może stworzyć strukturę menu, która pozwala na łatwe dodawanie nowych kategorii i pozycji bez zmiany istniejących.

  • Modularne menu: Właściciel tworzy system, w którym menu jest podzielone na sekcje: przystawki, dania główne, desery, wegańskie, bezglutenowe itd. Każda sekcja jest osobnym modułem, który można łatwo rozszerzyć, dodając nowe pozycje.
  • Dodawanie nowych pozycji: Gdy restauracja chce dodać nowe wegańskie przystawki, wystarczy, że dodadzą nowe dania do sekcji „Wegańskie przystawki”, nie zmieniając istniejących sekcji i dań. Właściciel może nawet dodawać całe nowe sekcje, np. „Specjalne dania sezonowe”, bez modyfikowania struktury istniejących sekcji.

Przykład programu przed użyciem zasady OCP:

Załóżmy, że tworzymy program, który obsługuje różne zwierzęta i pozwala im wydawać odgłosy. Mamy klasę AnimalSound, która obsługuje wydawanie odgłosów dla kilku typów zwierząt: psa, kota i krowy.

class AnimalSound {
    public void makeSound(String animalType) {
        if (animalType.equals("dog")) {
            System.out.println("Pies szczeka: Hał Hał!");
        } else if (animalType.equals("cat")) {
            System.out.println("Kot miauczy: Miał!");
        } else if (animalType.equals("cow")) {
            System.out.println("Krowa muczy: Muu!");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        AnimalSound animalSound = new AnimalSound();
        animalSound.makeSound("dog");
        animalSound.makeSound("cat");
        animalSound.makeSound("cow");
    }
}

Dlaczego ten kod łamie zasadę OCP?

  • Każde nowe zwierzę wymaga modyfikacji metody makeSound w klasie AnimalSound. Oznacza to, że kod nie jest otwarty na rozszerzenia, a jego modyfikacja wymaga ingerencji w już istniejący kod.

Poprawiony kod zgodny z zasadą OCP

Aby przestrzegać zasady OCP, możemy użyć dziedziczenia lub interfejsów. Każde zwierzę powinno być odpowiedzialne za wydawanie swojego odgłosu, a AnimalSound powinno być otwarte na rozszerzenia poprzez dodawanie nowych klas zwierząt.

// Interfejs definiujący metodę wydawania odgłosu
interface Animal {
    void makeSound();
}

class Dog implements Animal {
    @Override
    public void makeSound() {
        System.out.println("Pies szczeka: Hał Hał!");
    }
}

class Cat implements Animal {
    @Override
    public void makeSound() {
        System.out.println("Kot miauczy: Miał!");
    }
}

class Cow implements Animal {
    @Override
    public void makeSound() {
        System.out.println("Krowa muczy: Muu!");
    }
}

// Dodanie nowego zwierzęcia - Kaczka
class Duck implements Animal {
    @Override
    public void makeSound() {
        System.out.println("Kaczka kwacze: Kwa Kwa!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog();
        Animal cat = new Cat();
        Animal cow = new Cow();
        Animal duck = new Duck();

        dog.makeSound();
        cat.makeSound();
        cow.makeSound();
        duck.makeSound(); // Dodanie nowego zwierzęcia nie wymaga modyfikacji istniejącego kodu
    }
}

Podsumowanie

Poprawiona wersja kodu jest zgodna z zasadą Otwarte-Zamknięte (OCP), ponieważ umożliwia dodawanie nowych typów zwierząt bez konieczności modyfikowania istniejącego kodu. Dzięki zastosowaniu interfejsu ⁣Animal może być łatwo rozszerzany o nowe zwierzęta, co sprawia, że jest bardziej elastyczny i łatwiejszy do utrzymania.

Scroll to Top