Open Close Principle



Definicja

Zasada otwarte/zamknięte (ang. Open/Closed Principle, OCP) mówi, że klasy, moduły i funkcje powinny być otwarte na rozszerzenia, ale zamknięte na modyfikacje.
Oznacza to, że jeśli chcemy dodać nową funkcjonalność, powinniśmy móc to zrobić bez zmieniania istniejącego kodu, tylko poprzez jego rozszerzenie – np. przez dziedziczenie lub implementację interfejsu.

Przykład z życia

Wyobraźmy sobie fabrykę prefabrykatów W fabryce prefabrykatów istnieje linia produkcyjna, która może wytwarzać różne elementy: belki, płyty i słupy.
Na początku proces sterowania maszyną był przygotowany tylko dla belek. Gdy pojawiła się potrzeba produkcji płyt, trzeba było zmieniać oryginalny kod programu sterującego, co groziło wprowadzeniem błędów.

Lepszym rozwiązaniem jest stworzenie systemu, który można rozszerzyć o nowe typy prefabrykatów, bez ingerowania w już działający kod. Każdy nowy typ elementu ma wtedy własny moduł produkcyjny, który wpasowuje się w istniejącą strukturę.

Przykłady przed i po zastosowaniu zasady

PRZED

Poniższy przykład łamie zasadę OCP — każdorazowe dodanie nowego typu prefabrykatu wymaga modyfikacji klasy ProductionController.

Aby dodać np. słup prefabrykowany, trzeba otworzyć klasę i dodać kolejny warunek elif element_type == "column": ....
Z czasem taka klasa staje się trudna w utrzymaniu i podatna na błędy.

public class ProductionController {

    public void produce(String elementType) {
        if (elementType.equals("beam")) {
            System.out.println("Producing reinforced concrete beam...");
        } else if (elementType.equals("slab")) {
            System.out.println("Producing reinforced concrete slab...");
        } else {
            System.out.println("Unknown element type!");
        }
    }

    public static void main(String[] args) {
        ProductionController controller = new ProductionController();
        controller.produce("beam");
        controller.produce("slab");
        controller.produce("column");
    }
}
Designed by Freepik

PO

Po zastosowaniu zasady OCP rozdzielamy odpowiedzialności i umożliwiamy rozszerzanie funkcjonalności bez modyfikacji istniejącego kodu.

Teraz jeśli chcemy dodać nowy element, np. słup, wystarczy utworzyć nową klasę. I można ją natychmiast użyć — bez modyfikowania ProductionController.

// Klasa bazowa (abstrakcyjna)
abstract class PrefabElement {
    public abstract void produce();
}

// Klasa reprezentująca belkę prefabrykowaną
class Beam extends PrefabElement {
    @Override
    public void produce() {
        System.out.println("Producing reinforced concrete beam...");
    }
}

// Klasa reprezentująca płytę prefabrykowaną
class Slab extends PrefabElement {
    @Override
    public void produce() {
        System.out.println("Producing reinforced concrete slab...");
    }
}

// Kontroler produkcji – działa z dowolnym prefabrykatem
class ProductionController {
    private PrefabElement element;

    public ProductionController(PrefabElement element) {
        this.element = element;
    }

    public void runProduction() {
        element.produce();
    }
}

// Klasa główna – przykład użycia
public class Main {
    public static void main(String[] args) {
        PrefabElement beam = new Beam();
        PrefabElement slab = new Slab();

        ProductionController controller1 = new ProductionController(beam);
        controller1.runProduction();

        ProductionController controller2 = new ProductionController(slab);
        controller2.runProduction();
    }
}