Open Close Principle (OCP)

Understanding the SOLID Principles: The Open Close Principle(OCP)

Shahmir Khan
4 min readMar 6, 2025

When it comes to writing clean, maintainable, and scalable code, the SOLID principles are a set of guidelines that every developer should be familiar with. SOLID is an acronym that stands for five principles of object-oriented programming and design:

  1. Single Responsibility Principle
  2. Open/Closed Principle
  3. Liskov Substitution Principle
  4. Interface Segregation Principle
  5. Dependency Inversion Principle

In this article, we’ll focus on the Open/Closed Principle (OCP), which is the O in SOLID. We’ll explore what it means, why it’s important, and how you can apply it in JavaScript with practical examples.

What is the Open/Closed Principle?

The Open/Closed Principle states that:

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

In simpler terms, this means that you should design your code in such a way that you can add new functionality without changing the existing code. This principle encourages you to write code that is flexible and easy to extend, reducing the risk of introducing bugs when requirements change.

Why is the Open/Closed Principle Important?

  1. Maintainability: By adhering to OCP, you minimize the need to modify existing code, which reduces the chances of introducing bugs.
  2. Scalability: Your code becomes easier to extend as new requirements arise, making it more adaptable to change.
  3. Reusability: Code that follows OCP is often more modular and reusable, as it’s designed to be extended rather than rewritten.

Applying the Open/Closed Principle in JavaScript

JavaScript, being a flexible and dynamic language, allows us to implement the Open/Closed Principle in various ways. Let’s look at two examples to understand how this principle can be applied in practice.

A Problematic Example: Violating the Open/Closed Principle

Let’s start with an example that violates the Open/Closed Principle. Imagine we have an AreaCalculator class that calculates the area of different shapes. Here’s how it might look:

// Before
class AreaCalculator {
static calculate(shape) {
if (shape.type === "circle") {
return Math.PI * shape.radius ** 2;
} else if (shape.type === "square") {
return shape.side * shape.side;
} else if (shape.type === "triangle") {
console.log("AREA FOR TRIANGLE!");
}
}

static calculateAreas(shapes) {
return shapes.reduce(
(sum, shape) => sum + AreaCalculator.calculate(shape),
0
);
}
}

const circle = { type: "circle", radius: 5 };
const square = { type: "square", side: 4 };

console.log(AreaCalculator.calculate(circle)); // 78.54
console.log(AreaCalculator.calculate(square)); // 16

Issues with This Approach:

  1. Tight Coupling: The AreaCalculator class is tightly coupled to the specific shapes it knows about (e.g., circle, square, triangle). If you want to add a new shape, you must modify the calculate method.
  2. Violation of OCP: Every time a new shape is introduced, the AreaCalculator class needs to be modified, which violates the Open/Closed Principle.
  3. Poor Scalability: As the number of shapes grows, the calculate method becomes increasingly complex and harder to maintain.

Refactoring to Adhere to the Open/Closed Principle

To adhere to the Open/Closed Principle, we need to design our system in a way that allows us to add new shapes without modifying the existing code. Here’s how we can refactor the example:

// After adopting OCP
class Shape {
area() {
// OVERRIDE ME!!!!
console.log("SHAPE DID NOT IMPLEMENT AREA!");
}
}

class Circle extends Shape {
constructor(radius) {
super();
this.radius = radius;
}
area() {
return Math.PI * this.radius ** 2;
}
}

class Square extends Shape {
constructor(side) {
super();
this.side = side;
}
area() {
return this.side * this.side;
}
}

class Rectangle extends Shape {
constructor(length, width) {
super();
this.length = length;
this.width = width;
}
area() {
return this.length * this.width;
}
}

class AreaCalculator {
static calculate(shape) {
return shape.area();
}
static calculateAll(shapes) {
return shapes.reduce((sum, shape) => sum + shape.area(), 0);
}
}

const c = new Circle(5);
const s = new Square(5);
const r = new Rectangle(10, 20);

console.log(AreaCalculator.calculate(c)); // 78.54
console.log(AreaCalculator.calculate(s)); // 25
console.log(AreaCalculator.calculate(r)); // 200
console.log(AreaCalculator.calculateAll([c, s, r])); // 303.54

Key Improvements:

  1. Polymorphism: Each shape (e.g., Circle, Square, Rectangle) extends a base Shape class and implements its own area method. This allows the AreaCalculator to work with any shape without knowing its specific type.
  2. Extensibility: To add a new shape (e.g., a triangle), you simply create a new class that extends Shape and implements the area method. No changes are required in the AreaCalculator class.
  3. Closed for Modification: The AreaCalculator class is now closed for modification but open for extension. It doesn’t need to change when new shapes are introduced.

Key Takeaways

  1. Open for Extension: Design your code so that new functionality can be added easily, often through inheritance, composition, or configuration.
  2. Closed for Modification: Avoid changing existing code when adding new features. This reduces the risk of introducing bugs and keeps your codebase stable.
  3. Use Abstraction: Leverage abstractions (e.g., interfaces, higher-order functions) to make your code more flexible and extensible.

Conclusion

The Open/Closed Principle is a powerful guideline for designing flexible and maintainable software systems. By ensuring that your code is open for extension but closed for modification, you can build systems that are easier to scale and adapt to changing requirements.

In the next blog post, we’ll explore the Liskov Substitution Principle (LSP), the “L” in SOLID, and see how it complements the Open/Closed Principle. Stay tuned!

Sign up to discover human stories that deepen your understanding of the world.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Shahmir Khan
Shahmir Khan

Written by Shahmir Khan

Shahmir Khan have 5+ years of software development experience. He knows Javascript, PHP, ReactJS, NodeJS, VueJS and Laravel.

No responses yet

Write a response