WikiDer > Хрупкий базовый класс
Эта статья включает в себя список общих Рекомендации, но он остается в основном непроверенным, потому что ему не хватает соответствующих встроенные цитаты. (Сентябрь 2009 г.) (Узнайте, как и когда удалить этот шаблон сообщения) |
В проблема хрупкого базового класса фундаментальная архитектурная проблема объектно-ориентированного программирования системы, в которых базовые классы (суперклассы) считаются "хрупкими", потому что кажущиеся безопасными модификации базового класса при наследовании производные классы, может вызвать сбой в работе производных классов. Программист не может определить, безопасно ли изменение базового класса, просто изучив изолированно методы базового класса.
Одно из возможных решений - сделать переменные экземпляра закрытыми для их определяющего класса и заставить подклассы использовать методы доступа для изменения состояний суперкласса. Язык также может сделать так, чтобы подклассы могли контролировать, какие унаследованные методы открываются публично. Эти изменения не позволяют подклассам полагаться на детали реализации суперклассов и позволяют подклассам предоставлять только те методы суперкласса, которые применимы к ним сами.
Другим альтернативным решением может быть интерфейс вместо суперкласса.
Проблема хрупкости базового класса была возложена на открытая рекурсия (динамическая отправка методов на это
), с предположением, что вызов методов на это
по умолчанию используется закрытая рекурсия (статическая отправка, раннее связывание), а не открытая рекурсия (динамическая отправка, позднее связывание), только с использованием открытой рекурсии, когда это специально запрашивается; внешние звонки (без использования это
) будет динамически отправляться как обычно.[1][2]
Пример Java
Следующий тривиальный пример записан в Язык программирования Java и показывает, как кажущаяся безопасной модификация базового класса может вызвать сбой в работе наследующего подкласса путем ввода бесконечная рекурсия что приведет к переполнение стека.
учебный класс супер { частный int прилавок = 0; пустота inc1() { прилавок++; } пустота inc2() { прилавок++; }}учебный класс Sub расширяет супер { @Override пустота inc2() { inc1(); }}
Вызов динамически привязанного метода inc2 () на примере Sub правильно увеличит поле прилавок одним. Если же код суперкласса изменить следующим образом:
учебный класс супер { частный int прилавок = 0; пустота inc1() { inc2(); } пустота inc2() { прилавок++; }}
вызов динамически привязанного метода inc2 () на примере Sub вызовет бесконечную рекурсию между собой и методом inc1 () суперкласса и в конечном итоге вызовет переполнение стека. Этой проблемы можно было избежать, объявив методы в суперклассе как окончательный, что сделало бы невозможным их переопределение подклассом. Однако это не всегда желательно или возможно. Поэтому для суперклассов рекомендуется избегать изменения вызовов методов с динамической привязкой.
Решения
- Цель-C имеет категории а также нехрупкие переменные экземпляра.
- Компонент Паскаль осуждает вызовы суперкласса.
- Ява, C ++ (Начиная с C ++ 11) и D разрешить наследование или переопределение метода класса, которое должно быть запрещено, помечая объявление класса или метода, соответственно, ключевым словом "окончательный". В книге Эффективная Java, автор Джошуа Блох пишет (в пункте 17), что программисты должны «спроектировать и задокументировать наследование, иначе запретить это».
- C # и VB.NET как у Java "запечатанный" и "Не наследуется"ключевые слова объявления класса, запрещающие наследование и требующие, чтобы подкласс использовал ключевое слово"отменять"о методах переопределения,[3] то же решение позже было принято в Scala.
- Scala требуется подкласс для использования ключевого слова "отменять"явно, чтобы переопределить метод родительского класса. В книге" Программирование на Scala, 2-е издание "автор пишет, что (с изменениями здесь), если не было метода f (), исходная реализация клиентского метода f () не могло быть модификатора переопределения.Когда вы добавите метод f () во вторую версию класса библиотеки, перекомпиляция клиентского кода приведет к ошибке компиляции вместо неправильного поведения.
- Юля разрешает только подтипы абстрактных типов и использует композицию как альтернативу наследование. Однако он множественная отправка.
Смотрите также
- Проблема с хрупким двоичным интерфейсом
- Наследование реализации
- Семантика наследования
- Хрупкость программного обеспечения
- Виртуальное наследование (объектно-ориентированное программирование)
Рекомендации
внешняя ссылка
- Михайлов, Леонид; Секерински, Эмиль (1998). "Исследование проблемы хрупкого базового класса" (PDF). ECOOP’98 - Объектно-ориентированное программирование. ЭКООП 1998. LCNS. 1445. С. 355–382. Дои:10.1007 / BFb0054099. ISSN 0302-9743. QID 29543920. Получено 2020-07-21.
- Голуб, Аллен (1 августа 2003 г.). «Почему простирается зло». Панель инструментов Java. JavaWorld. Получено 2020-07-21.