Non-developer clients assume that when they ask for new features that the developer would just add to the code and not change anything which is working. Imagine the shock when they ask for a new feature and the features which were working are now broken or functioning differently. The client will be left wondering why you touched the old code or may assume that you are incompetent, but either way this breeds distrust in your abilities.

When modifying old code there is a chance of introducing bugs and it can be hard to modify behavior of an API which is already in use by many clients. For these reasons its better if we do not have to touch working code.

"Software entities should be open for extension but closed for modification." - Bertrand Meyer

We should be able to introduce new functionality by adding new classes and not by changing existing ones. This does not mean no class should ever get modified, there are exceptions such as bug fixing and the entry point to add the new class.

If you have a class to make an animal sound, you would have to check what type of animal it is first, like in the following method:


private string GetSound(IAnimal animal)
{
        if(animal is Lion)
        {
            return "Roar";
        }
        else if(animal is Rat)
        {
            return "Squeak";
        }
        else if(animal is Dog)
        {
            return "Woof";
        }
}
  

You may need to do the same thing in other classes, where you may need to determine which food to feed the animal or check if the animal is friendly. But then each time you work with an animal object you need to do checks to find out which animal was passed in.

That will work and it seems fine at first but the problem comes in when you add another animal to the system. You will then have to find all the places where animal logic needs to be added but you could miss a place and cause issues in production. Wouldn't it be easier and safer if all the logic for a given animal was in one place? Some concepts which will lead us toward OCP are: Dynamic Dispatch, Protected Variation and Single Choice Principle.

Open Closed Principle can be achieved with dynamic dispatch. Dynamic dispatch is the process of selecting which implementation of a polymorphic operation (method or function) to call at run time.


  private string GetSound(IAnimal animal)
  {
          animal.Speak();
  }
    

The GetAnimal() method selects which implementation of IAnimal to return, it could return a Lion or Rat, dynamically changing the behavior of Speak() at runtime.

Protect a class from the variations in the system by wrapping points of predicted variation with an interface. Then use dynamic dispatch to create various implementations of the interface. ie dont use a switch statement to decide on the functionality, rather inject a concrete class which has the functionality in it.

Whenever a software system must support a set of alternatives, one and only one module should know their exhaustive list. Isolate the responsibility of creating object variations to a single class, if anything needs to be extended it can be added in one place. EG a factory or DI container knows how to create the different classes, but will be the only class which has to be modified when a new class is added.


    private IAnimal GetAnimal()
    {
        switch(_environment)
        {
            case "African Plains":
                return new Lion();
            case "Bush":
                return new Rat();
            case "House":
                return new Dog();
        }
    }
  

By having a single class decide on which animal to return, all other classes which use the animal interface methods never have to be updated when a new animal is added.

  • Strategy pattern
  • Template method pattern
  • Visitor pattern
  • Chain of Responsibility pattern

Check out these links for more info:

My design and architecture repo