Language: English O’zbek

Open/Closed Principle (OCP)

Software entities should be open for extension but closed for modification.

You should be able to add new behavior without editing existing, tested code. This is typically achieved through inheritance and polymorphism.

Diagram

OCP class diagram

Violation

In violation.py an AreaCalculator uses isinstance checks to handle each shape type:

class AreaCalculator:
    @staticmethod
    def calculate(shape: object) -> float:
        if isinstance(shape, Rectangle):
            return shape.width * shape.height
        if isinstance(shape, Circle):
            return math.pi * shape.radius ** 2
        raise TypeError(f"Unknown shape: {type(shape).__name__}")

Adding a Triangle requires modifying the existing AreaCalculator — it is not closed for modification.

Correct

In correct.py a Shape abstract base class defines the area() contract. Each shape implements its own calculation:

class Shape(ABC):
    @abstractmethod
    def area(self) -> float: ...

class Triangle(Shape):
    def __init__(self, base: float, height: float) -> None:
        self.base = base
        self.height = height

    def area(self) -> float:
        return 0.5 * self.base * self.height

Adding a new shape is just a new subclass — zero changes to existing code.