Ключевое противоречие ООП Как известно, классический ООП держится на трёх китах:
Классическая реализация по умолчанию:- Инкапсуляция — публичные и частные члены класса
- Наследование — это реализация функциональности путем расширения одного класса-предка, защищенных членов класса.
- Полиморфизм — виртуальные методы класса-предка.
Наследование нарушает инкапсуляцию
- Защищенные члены класса-предка доступны классу-потомку.
Всем остальным доступен только публичный интерфейс класса.
Крайний случай взлома — антипаттерн Паблик Морозов ;
- Фактически изменить поведение предка можно, только переопределив виртуальные методы;
- Принцип замены Лискова обязывает класс-потомок удовлетворять всем требованиям, предъявляемым к классу-предку;
- Для выполнения пункта 2 в строгом соответствии с пунктом 3 классу-потомку необходима полная информация о времени вызова и реализации переопределенного виртуального метода;
- Информация в пункте 4 зависит от реализации класса-предка, включая частные члены и их код.
- Зависимость, создаваемая наследованием, чрезвычайно сильна;
- Наследники сверхчувствительны к любым изменениям предка;
- Наследование чужого кода добавляет адскую боль при обслуживании: разработчики библиотек рискуют столкнуться с препятствиями из-за нарушенной обратной совместимости при малейшем изменении базового класса, а разработчики приложений рискуют регрессировать при любом обновлении используемых ими библиотек.
это так плохо? Теоретическое решение Влияние проблемы можно смягчить, приняв определенные конвенции: 1. Защищенные участники не нужны Это соглашение исключает морозную публику как класс.
2. Методы виртуального предка ничего не делают Это соглашение позволяет объединить знания о реализации предка с независимостью реализации в потомке.
3. Виртуальные методы предка никогда не вызываются в его коде.
Это соглашение позволяет потомкам не зависеть от внутренней реализации предка, а также требует, чтобы все виртуальные методы были общедоступными.
4. Экземпляры-предки никогда не создаются.
Это соглашение позволяет нам избавиться от несоответствия между требованиями к виртуальным методам (контракт публичного класса) с одной стороны и обязательством ничего не делать (контракт защищенного класса) — с другой.
Теперь принцип подмены Лискова можно соблюдать, не вступая в порочную связь с частным содержанием предка.
5. У предка нет невиртуальных членов.
Учитывая предыдущие соглашения, невиртуальные члены предка становятся бесполезными и должны быть устранены.
Результат: если класс-предок состоит из публичных виртуальных пустых методов и требований к ним для потомков, то наследование больше не нарушает инкапсуляцию.
К.
?.
Д.
Попутно мы получаем возможность решить проблему ромба для случая множественного наследования от обычных предков.
Но это все теория, и нам нужно.
Практические решения
- Виртуальные фиктивные методы уже существуют во многих языках и носят гордое название абстрактный .
- Классы, экземпляры которых не могут быть созданы, также существуют во многих языках и даже имеют одинаковые классифицировать .
- Полное соблюдение этих соглашений на языке C++ использовалось в качестве образца для проектирования и реализации.
- И самое приятное: в C# и многих других языках соглашения реализованы как первоклассный элемент. "интерфейс" .
Происхождение названия очевидно — в результате соблюдения конвенций от класса остался только его публичный интерфейс.
И если от обычных классов множественное наследование встречается редко, то от интерфейсов оно доступно без каких-либо ограничений.
- Языки, где нет наследования от классов, но есть наследование от интерфейсов (например, Go), нельзя лишить звания объектно-ориентированных.
Более того, такая реализация ООП теоретически правильнее и безопаснее на практике.
- Наследование от обычных классов (имеющих реализацию) — крайне специфический и крайне опасный архаизм.
- Избегайте наследования реализаций без крайней необходимости.
- Используйте модификатор «sealed» (для .
NET) или его эквивалент для всех классов, кроме тех, которые специально предназначены для наследования реализации.
- Избегайте публичных незапечатанных классов: пока наследование остается в пределах его сборок, от него все равно можно получить некоторую выгоду, а вред ограничен.
Теги: #объектно-ориентированное проектирование #паттерны проектирования #антипаттерны #программирование #.
NET #проектирование и рефакторинг #C++ #ООП
-
Клиент Питерфм/Москвафм Про
19 Oct, 24 -
Миллион За Голову Пирата
19 Oct, 24