Open-Closed Principle (OCP)

The Open-Closed Principle is one of the key principles in object-oriented programming (part of SOLID principles). It states that:

  1. Open for extension – You should be able to add new functionality to a module, class, or function.
  2. Closed for modification – Once a module or class is written and tested, you shouldn’t modify its existing code.

Why is this important?

If we modify existing code, we risk introducing bugs into the system. By adhering to the OCP, we design our code to allow new features without disturbing or rewriting what already works.

OCP in Python: A Simple Example

The Problem Without OCP:

Let’s say we have a class for calculating product prices based on user types:

class Price:
    def calculate_price(self, user_type, amount):
        if user_type == "basic":
            return amount
        elif user_type == "premium":
            return amount * 1.2
        elif user_type == "vip":
            return amount * 1.5

This class works fine, but if we need to add a new user type (e.g., super vip), we’ll have to modify the existing code, which violates the Open-Closed Principle.

The Solution Using OCP:

We can redesign the code to follow the OCP by using inheritance, polymorphism, or design patterns like the Strategy Pattern.

from abc import ABC, abstractmethod

# Abstract base class (interface)
class PriceType(ABC):
    @abstractmethod
    def calculate(self, amount):
        pass

# Implementations for different user types
class BasicPrice(PriceType):
    def calculate(self, amount):
        return amount

class PremiumPrice(PriceType):
    def calculate(self, amount):
        return amount * 1.2

class VipPrice(PriceType):
    def calculate(self, amount):
        return amount * 1.5

# Main class using OCP
class Price:
    def __init__(self, price_type: PriceType):
        self.price_type = price_type

    def calculate_price(self, amount):
        return self.price_type.calculate(amount)

# Usage
basic = Price(BasicPrice())
premium = Price(PremiumPrice())
vip = Price(VipPrice())

print(basic.calculate_price(100))   # 100
print(premium.calculate_price(100)) # 120
print(vip.calculate_price(100))     # 150

Advantages of This Approach

Easier to add new types: For example, adding a new type SuperVipPrice only requires creating a new class that implements PriceType:

class SuperVipPrice(PriceType):
    def calculate(self, amount):
        return amount * 2.0

No changes are needed in the existing Price class.

Minimized risk of bugs: Existing, tested code remains untouched.

Better code organization: Each class has a single responsibility, making the codebase easier to maintain and extend.

Summary

The Open-Closed Principle encourages extending functionality without modifying existing code. In Python, this is achieved using techniques like inheritance, polymorphism, and design patterns. Following OCP ensures that your code is robust, flexible, and maintainable over time.

About the author

Vili M, PhD

With an extensive experience in programming, Vili has dedicated his career to developing innovative solutions and advancing technology. As an expert in programming, electromagnetic fields, robotics, and teaching skills, he combines academic knowledge with practical expertise to deliver impactful results.