Когда наследование от класса тебе вредит позже? - PullRequest
7 голосов
/ 05 сентября 2010

Можете ли вы предоставить сценарии, когда мы наследуем от класса, он работает какое-то время, но потом что-то еще меняется и вносит ошибку?Я придумал следующую ситуацию:

  • для реализации Rectangle-with-hole, мы наследуем от класса Rectangle.В конструкторе мы проверяем, что отверстие находится внутри прямоугольника
  • Позже кто-то добавляет новый метод Resize в класс Rectangle.Они не проверяют, находится ли отверстие все еще внутри.
  • После изменения размера у нас может быть прямоугольник с отверстиями с отверстиями не внутри прямоугольников, что является ошибкой.

ЧтоЕсть другие проблемы, которые я должен быть осторожен, если я решу использовать наследование объектов в C #.

Ответы [ 7 ]

6 голосов
/ 05 сентября 2010

То, что вы описываете, является одной из ловушек наследования.

Еще одна ловушка - глубокая иерархия наследования.Поток Stackoverflow на композиции поверх наследования .

5 голосов
/ 05 сентября 2010

Есть много способов, как изменение базового класса может повлиять на поведение производного класса.Что, если автор вдруг решил сделать класс sealed, например?

Как и любой интерфейс, он должен быть стабильным, если потребителям не требуется модификация.

Основное "правило" снаследование - это принцип Лисковской субстанции.Это говорит о том, что производный класс должен заменять базовый класс или другие производные от него классы.

Этот случай нарушает это правило, так как прямоугольник с отверстием не является прямоугольником.

Обычно лучше использовать интерфейсы для разделения поведения на разумные реализуемые куски.Такие интерфейсы обычно называют прилагательными, а не существительными.Например, имеет смысл отображать как прямоугольник, так и прямоугольник с отверстием, поэтому интерфейс может иметь значение IRenderable.Если его можно изменить, у вас может быть IResizable и т. Д. Они могут быть объединены в IShape, но вы должны быть осторожны, чтобы ваше определение Shape определяло только поведение в вашей проблемной области.

Непосредственнонаследование от другого класса может быть опасным, так как тогда вы будете связаны поведением этого класса.Если вам действительно нужно это сделать, лучше всего извлечь нужную реализацию в общий базовый класс (например, Rectangle : RectangleImplementation, IShape).

3 голосов
/ 05 сентября 2010

Это известно как проблема хрупкого базового класса .

Еще одна потенциальная проблема с наследованием в целом - это когда вы хотите использовать свой собственный базовый класс, но для фреймворка требуется определенный базовый класс (например, ContextBoundObject) вместо интерфейса.

1 голос
/ 05 сентября 2010

Вот почему разработчики языка C # для начинающих разработчиков добавили в язык ключевое слово загерметизированный .Используйте разумно.

И используйте кодовые контракты для проверки ваших инвариантов, чтобы получить раннее предупреждение о поломке.

0 голосов
/ 06 сентября 2010

Я думаю, это не связано с c # или наследованием.Что бы вы ни делали, это неизбежная проблема разработки программного обеспечения.

Лучшее и простое решение - ежедневно создавать код и выполнять модульное тестирование .

0 голосов
/ 05 сентября 2010

Лучше использовать -Decorator Pattern в таких случаях. Это обеспечивает лучший способ расширения.

Это может быть реализовано с использованием следующей диаграммы: alt text

Объект прямоугольника будет создан и обернут в объект HoleDecorator, который будет отвечать за предоставление отверстия. Когда изменение размера Rectangle выполнено, вызывается Resizing of HoleDecorator, это вызовет сначала изменение размера объекта Rectangle, а затем вызовет AddedBehavior для Hole Decorator, который укажет, что делать с отверстием, когда основной компонент изменен.

0 голосов
/ 05 сентября 2010

Не вызывайте виртуальный метод в конструкторе. См. Сообщения Эрика Липперта об этом ( часть 1 и часть 2 ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...