Open/Closed Principle

What is „Open/Closed Principle” (OCP) ?

It is the second rule of the SOLID design rules (it stands for O in SOLID acronym).

Definition

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.
 
     Mayer Bertrand

It means that if user would ask for a change in the program, you as a programmer should not modify already existing classes, but you should extend existing application only by adding a new classes and functionalities.

This goal is often achieved by dividing the system into components and preparing a hierarchy of their dependencies that would protect high-level components from changes made to low-level components.

Real-life example

Let’s say we have an vet application that check health of animals.

public class Launcher {

    public static void main(String[] args){
        Vet vet = new Vet();

        Object[] animals = {new Dog(), new Cat()};

        vet.checkPetsHealth(animals);
    }

}
public class Dog {
    public void checkHealth() {
        System.out.println("Checking dog health");
    }
}
public class Cat {
    public void checkHealth() {
        System.out.println("Checking cat health");
    }
}
public class Vet {
    public void checkPetsHealth(Object[] animals) {
        for (Object animal : animals) {
            if (animal instanceof Dog) {
                Dog dog = (Dog) animal;
                dog.checkHealth();
            } else if (animal instanceof Cat) {
                Cat cat = (Cat) animal;
                cat.checkHealth();
            }
        }
    }
}

UML diagram of our application:

After some time out vet decided to expand business and check the health of hamsters as well.

public class Hamster {
    public void checkHealth() {
        System.out.println("Checking hamster health");
    }
}
public class Vet {
    public void checkPetsHealth(Object[] animals) {
        for (Object animal : animals) {
            if (animal instanceof Dog) {
                Dog dog = (Dog) animal;
                dog.checkHealth();
            } else if (animal instanceof Cat) {
                Cat cat = (Cat) animal;
                cat.checkHealth();
            } else if (animal instanceof Hamster) {
                Hamster hamster = (Hamster) animal;
                hamster.checkHealth();
            }
        }
    }
}

It became clear, that it is impossible to extend functionality without modifying Vet class, due to that application at this moment does not meet OCP rule.

Let’s refactor the code according to OCP rule. In this case, polymorphism might be helpful. We should start with adding interface for all animal „clients”.

public interface Animal {
    void checkHealth();
}
public class Dog implements Animal {
    public void checkHealth() {
        System.out.println("Checking dog health");
    }
}
public class Cat implements Animal {
    public void checkHealth() {
        System.out.println("Checking cat health");
    }
}
public class Hamster implements Animal {
    public void checkHealth() {
        System.out.println("Checking hamster health");
    }
}

Thanks to that, we don’t need to check for a instance type in Vet class and therefore no modification is needed anymore in case of extending functionality.

public class Vet {
    public void checkPetsHealth(Animal[] animals) {
        for (Animal animal : animals) {
            animal.checkHealth();
        }
    }
}

UML diagram of our application after refactoring:

Why should I follow „Open/Closed Principle” ?

This rule helps to maintain the code, which is easy to extend and friendly for new features.

Posted in SOLID rulesTags:
Write a comment