Sobes.tech
Назад к вопросам
Junior — Middle
61

Какими способами можно обеспечить соблюдение принципа открытости/закрытости в программных модулях?

Компании, где спрашивали
Платформа

Ответ от нейросети

sobes.tech AI

Что хотят услышать интервьюеры:

Принцип открытости/закрытости означает, что модуль должен легко расширяться без изменения уже существующего кода. На практике это достигается через абстракции, полиморфизм, композицию и инверсию зависимостей. В C# обычно делают так, чтобы новое поведение добавлялось через новые классы, а не через правки старых.

Определение:

OCP (Open/Closed Principle) — это принцип, согласно которому программный модуль должен быть открыт для расширения и закрыт для модификации. Иными словами, когда появляется новая бизнес-логика, лучше добавлять новый код рядом с существующим, чем переписывать проверенный.

Соблюдать OCP помогают:

  • интерфейсы и абстрактные классы;
  • полиморфизм вместо switch/if по типам;
  • композиция вместо жесткой наследуемости;
  • стратегии, фабрики, декораторы, обработчики цепочек;
  • вынесение изменчивого поведения за границы основного модуля.

Пример использования:

Допустим, есть расчет скидки для разных типов клиентов. Вместо того чтобы расширять if/else при каждом новом типе, можно вынести поведение в отдельные реализации интерфейса.

public interface IDiscountPolicy
{
    decimal Calculate(decimal amount);
}

public class RegularDiscountPolicy : IDiscountPolicy
{
    public decimal Calculate(decimal amount) => amount;
}

public class VipDiscountPolicy : IDiscountPolicy
{
    public decimal Calculate(decimal amount) => amount * 0.9m;
}

public class OrderService
{
    private readonly IDiscountPolicy _discountPolicy;

    public OrderService(IDiscountPolicy discountPolicy)
    {
        _discountPolicy = discountPolicy;
    }

    public decimal GetFinalAmount(decimal amount)
    {
        return _discountPolicy.Calculate(amount);
    }
}

Если позже появится новая скидка, достаточно добавить новый класс, реализующий IDiscountPolicy, не меняя OrderService.

Пояснение кода:

  1. IDiscountPolicy задает контракт расчета скидки.
  2. RegularDiscountPolicy и VipDiscountPolicy реализуют разные правила без изменения клиентского кода.
  3. OrderService зависит не от конкретной реализации, а от абстракции.
  4. При замене скидки в контейнере DI или при создании объекта с другой реализацией поведение расширяется без правок OrderService.

Если рассматривать не код, а организационный подход, то принцип можно соблюдать так: выделять неизменяемое ядро, а вариативные правила выносить в отдельные модули, плагины или конфигурацию. Тогда изменения происходят в новых компонентах, а базовая логика остается стабильной.

Ключевые моменты:

  • Лучше расширять систему добавлением новых классов, чем править существующие.
  • Основной инструмент для OCP в C# — абстракции и полиморфизм.
  • Избегайте больших switch/if по типам, статусам и режимам работы.
  • Используйте композицию и внедрение зависимостей, чтобы подменять поведение.
  • OCP особенно хорошо работает вместе с принципом инверсии зависимостей.
  • Полное отсутствие изменений в коде невозможно, но цель — минимизировать рискованные правки в стабильной логике.