Ответ
Принцип открытости/закрытости (OCP) гласит: сущности должны быть открыты для расширения, но закрыты для модификации. Это означает, что вы можете добавлять новое поведение, не изменяя существующий, уже протестированный и работающий код.
Основной механизм — абстракция. Вместо того чтобы работать с конкретными классами, код должен зависеть от интерфейсов или абстрактных классов.
Плохой пример (нарушает OCP):
Каждый раз при добавлении новой фигуры нужно менять класс AreaCalculator.
public class AreaCalculator
{
public double CalculateArea(object shape)
{
if (shape is Rectangle rect)
return rect.Width * rect.Height;
else if (shape is Circle circle)
return Math.PI * circle.Radius * circle.Radius;
// Добавление нового `if` для Triangle нарушит принцип!
throw new ArgumentException("Unknown shape");
}
}
Хороший пример (соответствует OCP):
- Определяем абстракцию:
public interface IShape { double CalculateArea(); } - Реализуем конкретные сущности:
public class Rectangle : IShape { public double Width { get; set; } public double Height { get; set; } public double CalculateArea() => Width * Height; }
public class Circle : IShape { public double Radius { get; set; } public double CalculateArea() => Math.PI Radius Radius; }
3. **Создаем расширяемый калькулятор:**
```csharp
public class AreaCalculator
{
// Этот метод теперь ЗАКРЫТ для модификаций.
// Чтобы добавить поддержку новой фигуры, мы НЕ меняем этот код.
public double TotalArea(IEnumerable<IShape> shapes)
{
return shapes.Sum(shape => shape.CalculateArea());
}
}
- Расширяем систему (добавляем новую фигуру):
public class Triangle : IShape { public double Base { get; set; } public double Height { get; set; } public double CalculateArea() => 0.5 * Base * Height; } // Класс `AreaCalculator` продолжает работать без изменений!
Паттерны, помогающие следовать OCP:
- Стратегия (Strategy): Инкапсулирует семейство алгоритмов, делая их взаимозаменяемыми.
- Декоратор (Decorator): Динамически добавляет новую функциональность объекту.
- Наблюдатель (Observer): Позволяет подписываться на события, не изменяя код издателя.