Нарушает ли переопределение принцип Open/Closed?
Принцип открытия / закрытия гласит, что класс должен быть открыт для расширения, но закрыт для модификации.
Я думал, что часть модификации относится исключительно к изменению исходного кода базового класса. Но я поспорил с кем-то, кто сказал, что это также включает переопределение методов из базового класса.
Правильно ли это толкование?
4 ответа
Виртуальные методы позволяют заменять поведение базового класса в производном классе, не изменяя базовый класс, и это означает, что вы придерживаетесь принципа Open/Closed, поскольку вы можете расширять систему без необходимости изменять существующий код.
Базовые классы (которые не являются чисто абстрактными), тем не менее, имеют тенденцию нарушать принцип обращения зависимостей, поскольку производный класс получает зависимость от базового класса, который является конкретным компонентом, а не абстракцией. Помните, что DIP утверждает, что:
Модули высокого уровня должны [...] зависеть от абстракций.
Помимо этого, базовые классы также имеют тенденцию нарушать принцип разделения интерфейса в случае, если они определяют несколько открытых (или защищенных) методов, которые не все используются производным типом. Это нарушение интернет-провайдера, потому что:
ни один клиент не должен зависеть от методов, которые он не использует
"Я думал, что часть модификации относится исключительно к изменению исходного кода базового класса".
Вы думали правильно.
Существует множество способов сделать класс расширяемым, и один из них позволяет наследовать его. Ключевое слово extend
даже используется в нескольких языках для включения наследования, что делает совершенно очевидным, что мы не модифицируем, мы расширяем...
Является ли наследование правильным решением для расширяемости или нет, это другая проблема, но обычно это не так. Композиция должна быть предпочтительным способом сделать класс расширяемым (например, Стратегия, Наблюдатель, Декоратор, Трубы и Фильтры и т. Д.)
Переопределение очень похоже на обратный вызов, который любой может зарегистрировать. Это как:
if (IsOverridden) CallCallback();
else DefaultImplementation(); //possibly empty
В этом смысле нет изменений. Вы просто переконфигурируете объект для вызова обратного вызова вместо того, чтобы выполнять поведение по умолчанию.
Это как событие нажатия кнопки. Вы бы не посчитали подписку на событие модификацией. Это расширение.
Форма "Адаптивный код через C#" книга, виртуальные методы это инструмент для достижения OCP.