hat Is the Open/Closed Principle?

The Open/Closed Principle says:

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

In simpler words:

  • Open for extension: It should be possible to add new behavior by writing new code.

  • Closed for modification: You should avoid changing existing, stable code every time you add something new.

The main idea is:

  • Once a class is tested and working, you want to protect it from constant changes.

  • Instead of editing it, you extend its behavior using interfaces, inheritance, and polymorphism.

OCP does not mean “never touch old code again.”
It means “design your important pieces so that new features go into new classes, not into long if/else chains inside existing ones.”

A “Bad” Design That Breaks OCP

Start with a simple example: calculating the total area of shapes.

First Attempt: One Class That Knows All Shapes

Problems:

  • AreaCalculator Needs to know every shape type.

  • If you add TriangleYou must:

    • Change AreaCalculator’s parameters.

    • Add a new loop and area formula inside AreaCalculator.

Every time a new shape is added, AreaCalculator must be modified.
This clearly breaks OCP.

Even worse, in real systems, the “calculator” might be big, complex, and used everywhere. Regularly editing it increases the risk of bugs.

Applying OCP: Introduce an Abstraction

To follow OCP, move the varying part (area calculation per shape) out of AreaCalculator and into each shape.

Step 1: Create a Shape Abstraction


This defines what all shapes must do: provide an area() method.
Shape is our abstraction.

Step 2: Make Each Shape Implement Its Own Area

Now:

  • Rectangle knows how to compute its own area.

  • Circle knows how to compute its own area.No longer needs to know the formulas for each type.

Step 3: Rewrite AreaCalculator to Use the Abstraction

Usage:

Now, if you want a new Triangle:

You do not touch AreaCalculator at all.
You just create Triangle objects and put them into the shapes vector.

This design is:

  • Closed for modification: AreaCalculator doesn’t need changes.

  • Open for extension: new shapes are added by writing new classes that implement Shape.

That is OCP in practice.

OCP in a More Realistic LLD Example: Payment Methods

Shapes are nice, but LLD questions are often about services like payments.

Suppose you have a CheckoutService that charges a user.
You start with card payments.

Version that Violates OCP


Whenever you add UPI, netbanking, or another method, you must edit this if/else block.
This is exactly what OCP wants you to avoid.

OCP-Friendly Version Using an Interface

Step 1: Define a payment abstraction:


Step 2: Implement specific methods:


Step 3: Let CheckoutService depend on the abstraction:


Usage:


If you later add UPIPaymentYou only create a new class implementing PaymentMethod.
CheckoutService stays unchanged, so it follows OCP.

How to Think About OCP When Designing

When designing classes for LLD, ask:

  1. Where do I expect variation in the future?

    • More payment methods?

    • More notification channels?

    • More pricing strategies?

    • More types of tickets or reports?

  2. Are those variations currently handled by if/else or switch on type?

    • If yes, that code will need modification every time a new type is added.

  3. Can I move the varying behavior into separate classes behind an interface?

    • Define an abstraction (Notifier, PaymentMethod, PricingStrategy).

    • Let existing code depend only on that abstraction.

    • Add new behavior by adding new classes, not by editing old ones.

In short, OCP often leads you to:

  • Create interfaces or abstract classes.

  • Use polymorphism instead of big conditional blocks.

  • Inject dependencies (pass them into constructors or methods) instead of instantiating concrete classes inside.

Quick Checklist for OCP

Use this as a simple checklist while reviewing your design:

  • Does this class have a big switch or if/else That depends on a “type” or “mode”?

  • When a new type is added, do you have to edit several existing classes?

  • Can you pull that variation into a separate interface and have different classes implement it?

  • Can higher-level classes depend only on the interface instead of concrete implementations?

If you answer “yes” to the first two questions and “no” to the last two, then you probably have an OCP violation.

Summary

The Open/Closed Principle says that classes should be open for extension but closed for modification.
That means you can add new features (new shapes, new payment methods, new strategies) by adding new classes, not by constantly editing existing, stable ones.

In this article, you learned:

  • The formal idea of OCP and a simple explanation in beginner-friendly language.

  • A “bad” area-calculation design that breaks OCP, and how to refactor it using an.

  • A more realistic payment example where CheckoutService depends on a PaymentMethod abstraction instead of concrete if/else logic.

  • How to think about future variation, define abstractions, and structure your code so new behavior comes from new classes.

  • A small checklist to help you spot and fix OCP violations in your own Low-Level Designs.

Used together with the Single Responsibility Principle, OCP helps you design systems where core classes stay stable, and new features are plugged in cleanly through well-designed abstractions and implementations.