Code Quality Design Help

Open Closed Principle (OCP)

Overview

A software module should be open for extension but closed for modification. (Martin, 2002: 99)

Core Concepts

The OCP is at the heart of many of the claims made for OOD. (Martin, 2002: 125)

The gist is that for software systems to be easy to change, they must be designed to allow the behavior of those systems to be changed by adding new code, rather than changing existing code.

OCP relates to the Single Responsibility Principle (SRP) and Dependency Inversion Principle (DIP).

Clearly, some new code must be written. But how much old code will have to change?

  • We should reduce the amount of changed code to the barest minimum. Ideally, zero.

  • How? By properly separating the things that change for different reasons (SRP), and then organizing the dependencies between those things properly (DIP). (Martin, 2017: 70)

Implementation Examples

public class AreaCalculator { public double SumAreas(IShape[] shapes) { double sum = 0; foreach (var shape in shapes) { sum += shape.CalculateArea(); } return sum; } }

This calculator is open for extension because new IShape implementations can be added, yet closed for modification as the SumAreas logic itself doesn't need to change to accommodate them.

public static T Max<T>(T first, T second) where T : IComparable<T> { return first.CompareTo(second) >= 0 ? first : second; }

This generic method is closed for modification but open to work with any new types T that fulfill the IComparable<T> contract, demonstrating extension through Static Polymorphism and constraints.

Relation to Liskov Substitution Principle (LSP)

OCP also relates to the Liskov Substitution Principle (LSP). Violations of the LSP often force developers into using special type checks or conditional logic, which undermines the Open-Closed Principle by requiring modifications in existing code.

public class AreaCalculator_Violating_OCP { public double SumAreas(IEnumerable<IShape> shapes) { double sum = 0; foreach (var shape in shapes) { if (shape is SpecialConcreteShape specialShape) { // Custom logic for SpecialConcreteShape sum += specialShape.BaseValue; } else { // Original logic for other shapes sum += shape.CalculateArea(); } } return sum; } }

Adding the if (shape is SpecialConcreteShape) check violates the Open-Closed Principle, as it requires modifying the existing SumAreas method. This modification becomes necessary when SpecialConcreteShape cannot be transparently substituted for IShape (violating the Liskov Substitution Principle) because it demands unique handling by the calculator.

Software Entropy naturally increases as changes are made to the codebase. If developers don't actively work against this tendency, modifications like these type checks will continue to be added, degrading the system over time.

See Also:

01 May 2025