Ответ
Принцип открытости/закрытости (Open-Closed Principle, OCP) — один из пяти принципов SOLID, который гласит:
Программные сущности (классы, модули, функции и т.д.) должны быть открыты для расширения, но закрыты для модификации.
Это означает, что вы должны иметь возможность добавлять новую функциональность (открыт для расширения) без изменения существующего, уже протестированного кода (закрыт для модификации). Соблюдение OCP повышает стабильность, поддерживаемость и гибкость системы, снижая риск появления ошибок при добавлении новых возможностей.
Пример нарушения OCP:
Представим калькулятор площади, который напрямую зависит от конкретных типов фигур. При добавлении новой фигуры (Circle), придется изменять AreaCalculator.
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
class Circle:
def __init__(self, radius):
self.radius = radius
class AreaCalculator:
def calculate(self, shapes):
total = 0
for shape in shapes:
if isinstance(shape, Rectangle):
total += shape.width * shape.height
elif isinstance(shape, Circle): # При добавлении Circle, пришлось модифицировать AreaCalculator
total += 3.14 * shape.radius ** 2
return total
Правильный подход с соблюдением OCP:
Используя абстракции (интерфейсы или абстрактные классы) и полиморфизм, мы можем расширять систему, не изменяя существующий код.
from abc import ABC, abstractmethod
import math
class Shape(ABC):
@abstractmethod
def area(self) -> float:
"""Возвращает площадь фигуры."""
pass
class Rectangle(Shape):
def __init__(self, width: float, height: float):
self.width = width
self.height = height
def area(self) -> float:
return self.width * self.height
class Circle(Shape):
def __init__(self, radius: float):
self.radius = radius
def area(self) -> float:
return math.pi * self.radius ** 2
class AreaCalculator:
def calculate(self, shapes: list[Shape]) -> float:
"""Вычисляет общую площадь списка фигур."""
return sum(shape.area() for shape in shapes)
# Теперь можно легко добавить новую фигуру (например, Triangle), не изменяя AreaCalculator
class Triangle(Shape):
def __init__(self, base: float, height: float):
self.base = base
self.height = height
def area(self) -> float:
return 0.5 * self.base * self.height
# Использование:
calculator = AreaCalculator()
shapes_list = [
Rectangle(10, 5),
Circle(7),
Triangle(4, 6)
]
print(f"Общая площадь: {calculator.calculate(shapes_list)}")
В этом примере AreaCalculator закрыт для модификации, потому что он работает с абстракцией Shape. Чтобы добавить новую фигуру, достаточно создать новый класс, реализующий Shape, без изменения AreaCalculator. Это делает систему более гибкой и устойчивой к изменениям.