Open Closed Principle

Definition:

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

Description:

The class behavior should be extendable without modifying it. The class should be flexiable to extend for adding new functionality and the same class should not be modified for adding new funcationality.

Impact of OCP vialoation:

When a single change in a program, that affects the other places of a program is considered as vialoation of Open Closed Principle. This is making considerable impact in a program. We should design a program in such a manner, that is flexible to accodamate the new changes without modifying already tested code.

How can we change the behavior of a class without modifying it?

Abstraction & Polymorphism are key concepts, helps us to change the behavior of a class without modifying it.

Example for OCP Vialoation:

Ocp Vialoation

CuisineType : Enumeration with American, Asian, European and Oceanian Cuisine Types.

MealPreparation : Class having MealPrep method, executing prepare pancake method(PrepareAmericanCuisinePanCake, PrepareAsianCuisinePanCake, PrepareEuropeanCuisinePanCake or PrepareOceanianCuisinePanCake) based on cuisine type.

public enum CuisineType
{
    American = 1,
    Asian = 2,
    European = 3,
    Oceanian = 4
}
    
public class MealPreparation
{
    public void MealPrep(CuisineType cuisineType)
    {
        switch (cuisineType)
        {
            case CuisineType.American:
                PrepareAmericanCuisinePanCake();
                break;

            case CuisineType.Asian:
                PrepareAsianCuisinePanCake();
                break;

            case CuisineType.European:
                PrepareEuropeanCuisinePanCake();
                break;

            case CuisineType.Oceanian:
                PrepareOceanianCuisinePanCake();
                break;
        }
    }

    private void PrepareAmericanCuisinePanCake()
    {
        Console.WriteLine("American cuisine Pancake is ready !");
    }

    private void PrepareAsianCuisinePanCake()
    {
        Console.WriteLine("Asian cuisine Pancake is ready !");
    }

    private void PrepareEuropeanCuisinePanCake()
    {
        Console.WriteLine("European cuisine Pancake is ready !");
    }

    private void PrepareOceanianCuisinePanCake()
    {
        Console.WriteLine("Oceanian cuisine Pancake is ready !");
    }
}
    
class OcpViolation
{
    static void Main(string[] args)
    {
        var mealPreparation = new MealPreparation();
        mealPreparation.MealPrep(CuisineType.American);

        Console.ReadLine();
    }
}

Where is the violation ?

The MealPreparation class supports to prepare pancake for four types of Cuisines(American,Asian,European and Oceanian) . MealPrep(CuisineType cuisineType) method accepts cuisine type from user and prepare the pancake based on cuisine type. If we need to add another cuisine type, then we are expected to make change in MealPrep(CuisineType cuisineType) method and add another method for new cuisine type. This vialotes the Open Closed Principle. This current class design is not supported to add new cuisine type without making changes in MealPreparation class. Open for extension is not supported in this class design.

How Abstraction and Polymorphism helps to fix Open Closed Principle vialoation issue?

IMealPreparation interface(Abstraction) declares PreparePanCake method. AmericanCuisinePanCake, AsianCuisinePanCake, EuropeanCuisinePanCake and OceanianCuisinePanCake class implements IMealPreparation interface. Creating instance of AmericanCuisinePanCake class and assigns to IMealPreparation interface variable provides polymorphic behavior to execute PreparePanCake() method. This program is supported to create instance for any of AmericanCuisinePanCake, AsianCuisinePanCake, EuropeanCuisinePanCake and OceanianCuisinePanCake concrete class and execute the PreparePanCake() method(Polymorphism).

Fix for OCP Vialoation:

Fix Ocp Vialoation
// Abstraction
public interface IMealPreparation
{
    void PreparePanCake();
}

public class AmericanCuisinePanCake : IMealPreparation
{

    public void PreparePanCake()
    {
        Console.WriteLine("American cuisine Pancake is ready !");
    }
}

public class AsianCuisinePanCake : IMealPreparation
{

    public void PreparePanCake()
    {
        Console.WriteLine("Asian cuisine Pancake is ready !");
    }
}

public class EuropeanCuisinePanCake : IMealPreparation
{

    public void PreparePanCake()
    {
        Console.WriteLine("European cuisine Pancake is ready !");
    }
}

public class OceanianCuisinePanCake : IMealPreparation
{

    public void PreparePanCake()
    {
        Console.WriteLine("Oceanian cuisine Pancake is ready !");
    }
}

class Ocp
{
    static void Main(string[] args)
    {
        //Polimorphism
        IMealPreparation mealPreparation = new AmericanCuisinePanCake();
        mealPreparation.PreparePanCake();

        Console.ReadLine();
    }
}

The above code supports the extension without modifying existing code. We can create new class for each cuisine type and it must implement IMealPreparation interface. In this design, new cuisine type shall be added without modifying existing behaviour and its eliminated the cusine type checking with switch statement. Thus, satified Open Closed principle.