Jump to content

Хрупкий базовый класс

Проблема хрупкого базового класса — это фундаментальная архитектурная проблема систем объектно-ориентированного программирования , в которых базовые классы ( суперклассы ) считаются «хрупкими», поскольку кажущиеся безопасными модификации базового класса при наследовании производными классами могут привести к сбоям в работе производных классов. . Программист не может определить, безопасно ли изменение базового класса, просто исследуя методы базового класса по отдельности.

Одним из возможных решений является сделать переменные экземпляра частными для их определяющего класса и заставить подклассы использовать методы доступа для изменения состояний суперкласса. Язык также может сделать так, чтобы подклассы могли контролировать, какие унаследованные методы будут доступны публично. Эти изменения не позволяют подклассам полагаться на детали реализации суперклассов и позволяют подклассам предоставлять только те методы суперкласса, которые применимы к ним самим.

Альтернативное решение — использовать интерфейс вместо суперкласса.

В проблеме хрупкого базового класса обвиняют открытую рекурсию (динамическую отправку методов на this), с предположением, что вызов методов на this по умолчанию используется закрытая рекурсия (статическая диспетчеризация, раннее связывание), а не открытая рекурсия (динамическая диспетчеризация, позднее связывание), открытая рекурсия используется только тогда, когда это специально запрошено; внешние вызовы (без использования this) будет динамически отправляться, как обычно. [1] [2]

Пример Java

[ редактировать ]

Следующий тривиальный пример написан на языке программирования Java и показывает, как, казалось бы, безопасная модификация базового класса может привести к сбою в работе наследующего подкласса из-за входа в бесконечную рекурсию , что приведет к переполнению стека .

class Super {
    private int counter = 0;

    void inc1() {
        counter++;
    }

    void inc2() {
        counter++;
    }
}

class Sub extends Super {
    @Override
    void inc2() {
        inc1();
    }
}

Вызов динамически связанного метода inc2() в экземпляре Sub правильно увеличит счетчик поля на единицу. Однако если код суперкласса изменить следующим образом:

class Super {

    private int counter = 0;

    void inc1() {
        inc2();
    }

    void inc2() {
        counter++;
    }
}

вызов динамически связанного метода inc2() в экземпляре Sub вызовет бесконечную рекурсию между ним и методом inc1() суперкласса и в конечном итоге вызовет переполнение стека. Этой проблемы можно было бы избежать, объявив методы суперкласса как Final , что сделало бы невозможным их переопределение подклассом. Однако это не всегда желательно и возможно. Поэтому суперклассам рекомендуется избегать изменения вызовов динамически привязанных методов.

  • В Objective-C есть категории, а также нехрупкие переменные экземпляра .
  • Компонентный Паскаль не поддерживает вызовы суперклассов .
  • Java , C++ (начиная с C++11) и D позволяют запретить наследование или переопределение метода класса, пометив объявление класса или метода соответственно ключевым словом " finalВ книге «Эффективная Java » автор Джошуа Блох пишет (в пункте 17), что программисты должны «Проектировать и документировать наследование или запретить его».
  • В C# и VB.NET, как и в Java, есть " sealed" и " Not Inheritable" Ключевые слова объявления класса, чтобы запретить наследование и потребовать, чтобы подкласс использовал ключевое слово " override"о переопределении методов, [3] то же решение позже было принято в Scala.
  • Scala требует, чтобы подкласс использовал ключевое слово " override" явно для того, чтобы переопределить метод родительского класса. В книге "Программирование на Scala, 2-е издание" автор пишет, что (с изменениями здесь) Если не было метода f(), исходная клиентская реализация метода f() не могло быть модификатора переопределения. Как только вы добавите метод f() во вторую версию класса вашей библиотеки, перекомпиляция клиентского кода приведет к ошибке компиляции вместо неправильного поведения.
  • В Котлине классы и методы по умолчанию являются окончательными. Чтобы включить наследование классов, класс должен быть помечен значком open модификатор. Аналогично, метод должен быть помечен как open чтобы разрешить переопределение метода.
  • Julia допускает только подтипирование абстрактных типов и использует композицию в качестве альтернативы наследованию . Однако он имеет несколько отправок .

См. также

[ редактировать ]
  1. ^ « Выборочная открытая рекурсия: решение проблемы хрупкого базового класса », Джонатан Олдрич
  2. ^ « Выборочная открытая рекурсия: решение проблемы хрупкого базового класса », Lambda the Ultimate
  3. ^ «Модификатор переопределения — Справочник по C#» .
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 9bf20fed4a76fe9d0f96747458c409bf__1705775400
URL1:https://arc.ask3.ru/arc/aa/9b/bf/9bf20fed4a76fe9d0f96747458c409bf.html
Заголовок, (Title) документа по адресу, URL1:
Fragile base class - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)