Имея Circle
простиратьсяEllipse
перерывам в Лиск Substition принципе , потому что она изменяет постусловие , а именно: вы можете установить X и Y независимо друг от друга , чтобы нарисовать эллипс, но X всегда должен быть равен Y для окружностей.
Но разве проблема не в том, что круг является подтипом эллипса? Разве мы не можем изменить отношения?
Итак, Circle - это супертип - у него один метод setRadius
.
Затем Ellipse расширяет круг, добавляя setX
и setY
. Вызов setRadius
Ellipse установит и X, и Y - это означает, что постусловие на setRadius сохраняется, но теперь вы можете устанавливать X и Y независимо через расширенный интерфейс.
object-oriented
solid
liskov-substitution
HorusKol
источник
источник
Ответы:
Проблема с этим (и проблема квадрата / прямоугольника) ложно предполагает, что отношения в одной области (геометрия) сохраняются в другой (поведение)
Круг и эллипс связаны, если вы просматриваете их через призму геометрической теории. Но это не единственный домен, на который вы можете посмотреть.
Объектно-ориентированный дизайн имеет дело с поведением .
Определяющей характеристикой объекта является поведение, за которое он отвечает. А в области поведения круг и эллипс ведут себя так по-разному, что, вероятно, лучше вообще не думать о них как о связанных. В этой области эллипс и круг не имеют существенных отношений.
Урок здесь состоит в том, чтобы выбрать домен, который является наиболее подходящим для OOD, а не пытаться рожать в отношениях просто потому, что он существует в другом домене.
Наиболее распространенный реальный пример этой ошибки - предположить, что объекты связаны (или даже один и тот же класс), потому что они имеют схожие данные, даже если их поведение сильно отличается. Это распространенная проблема, когда вы начинаете конструировать объекты «сначала данные», определяя, куда идут данные. Вы можете получить класс, связанный через данные с совершенно другим поведением. Например, как ведомость платежа, так и объекты работника могут иметь атрибут «брутто-зарплата», но работник не является типом зарплаты, а ведомость не является типом работника.
источник
Круги являются частным случаем эллипсов, а именно, что обе оси эллипса одинаковы. В области задачи (геометрии) неверно утверждать, что эллипсы могут быть своего рода кругом. Использование этой некорректной модели нарушит многие гарантии круга, например, «все точки на круге имеют одинаковое расстояние до центра». Это тоже будет нарушением принципа подстановки Лискова. Как эллипс будет иметь один радиус? (Но не
setRadius()
более важноgetRadius()
)Хотя моделирование кругов как подтипа эллипсов не является в корне неверным, именно введение изменчивости нарушает эту модель. Без
setX()
иsetY()
методов, нет никакого нарушения LSP. Если необходимо иметь объект с разными размерами, лучше создать новый экземпляр:источник
Ellipse
иCircle
(напримерgetArea
) , которые были бы абстрагируются к типуShape
- можетEllipse
иCircle
отдельно от подтипаShape
и удовлетворяют LSP?У Кормака действительно отличный ответ, но я просто хочу немного рассказать о причине путаницы.
Наследование в ОО часто преподается с использованием реальных метафор, типа «яблоки и апельсины являются подклассами фруктов». К сожалению, это приводит к ошибочному убеждению, что типы в ОО должны моделироваться в соответствии с некоторыми таксономическими иерархиями, существующими независимо от программы.
Но при разработке программного обеспечения типы должны моделироваться в соответствии с требованиями приложения. Классификации в других областях обычно не имеют значения. В реальном приложении с объектами «Apple» и «Orange» - скажем, системой управления запасами для супермаркета - они, вероятно, вообще не будут отдельными классами, а такие категории, как «Фрукты», будут скорее атрибутами, чем супертипами.
Проблема круга-эллипса - красная сельдь. В геометрии круг - это специализация эллипса, но классы в вашем примере не являются геометрическими фигурами. Важно отметить, что геометрические фигуры не являются изменчивыми. Они могут быть преобразованы , хотя, но тогда круг может быть преобразован в многоточие. Таким образом, модель, в которой окружности могут изменять радиус, но не изменяться на многоточие, не соответствует геометрии. Такая модель может иметь смысл в конкретном приложении (скажем, инструмент для рисования), но геометрическая классификация не имеет отношения к тому, как вы проектируете иерархию классов.
Так должен ли Круг быть подклассом Эллипса или наоборот? Это полностью зависит от требований конкретного приложения, которое использует эти объекты. Приложение для рисования может иметь различные варианты обработки кругов и эллипсов:
Обрабатывайте круги и эллипсы как отдельные типы фигур с различным пользовательским интерфейсом (например, две ручки изменения размера на многоточии, одна ручка на круге). Это означает, что вы можете иметь эллипс, который геометрически является кругом, но не кругом с точки зрения приложения.
Обрабатывайте все эллипсы, включая кружки, одинаково, но есть возможность «зафиксировать» x и y на одном значении.
Эллипсы - это просто круги, где применяется масштабное преобразование.
Каждый возможный дизайн приведет к различной модели объекта -
В 1 - ом случае, Круг и эллипсы будут двойников классы
Во 2-м классе не будет отдельного класса Circle.
В третьем классе не будет отдельного класса Ellipse. Таким образом, так называемая проблема круг-эллипс не входит в картину ни в одном из них.
Таким образом, чтобы ответить на поставленный вопрос: должен ли круг расширять эллипс? Ответ: это зависит от того, что вы хотите с ним делать. Но, вероятно, нет.
источник
С самого начала было ошибкой настаивать на наличии классов «Ellipse» и «Circle», где один является подклассом другого. У вас есть два реалистичных варианта: один - иметь отдельные классы. Они могут иметь общий суперкласс для таких вещей, как цвет, заполнение объекта, ширина линии для рисования и т. Д.
Другой - иметь только один класс с именем "Ellipse". Если у вас есть этот класс, его достаточно просто использовать для представления окружностей (могут быть ловушки в зависимости от деталей реализации; у эллипса будет некоторый угол, и вычисление этого угла не должно создавать проблем для эллипса в форме круга). Вы могли бы даже иметь специализированные методы для круглых эллипсов, но эти "круглые эллипсы" все равно были бы полными объектами "эллипса".
источник
Следуя пунктам LSP, одно «правильное» решение этой проблемы заключается в том, что натолкнулись @HorusKol и @Ixrec - вывод обоих типов из Shape. Но это зависит от модели, с которой вы работаете, поэтому вы всегда должны вернуться к этому.
То, чему меня учили, это:
Если подтип не может выполнять то же поведение, что и супертип, отношение не сохраняется в предпосылке IS-A - его следует изменить.
По-английски:
(Пример:
Вот как работает классификация (т.е. в мире животных) и, в принципе, в ОО.
Используя это как определение наследования и полиморфизма (которые всегда пишутся вместе), если этот принцип нарушается, вы должны попытаться переосмыслить типы, которые вы пытаетесь смоделировать.
Как уже упоминалось @HorusKul и @Ixrec, в математике у вас есть четко определенные типы. Но в математике круг - это эллипс, потому что это ПОДПИСЬ эллипса. Но в ООП наследование не работает. Класс должен наследоваться только в том случае, если он является SUPERSET (расширением) существующего класса, то есть он все еще является базовым классом во всех контекстах.
Исходя из этого, я думаю, что решение должно быть слегка перефразировано.
Имейте базовый тип Shape, затем RoundedShape (фактически круг, но я использовал другое имя здесь СВОБОДНО ...)
... затем Эллипс.
Сюда:
(Это теперь имеет смысл для людей на языке. У нас уже есть четко определенная концепция «круга», и то, что мы пытаемся сделать здесь, обобщая (агрегирование), нарушает эту концепцию.)
источник
С точки зрения ОО эллипс расширяет круг, он специализируется на нем, добавляя некоторые свойства. Существующие свойства круга все еще сохраняются в эллипсе, он просто становится более сложным и более конкретным. Я не вижу никаких проблем с поведением в этом случае, как Cormac, формы не имеют поведения. Единственная проблема заключается в том, что в лингвистическом или математическом смысле неправильно говорить, что «эллипс - это круг». Потому что весь смысл упражнения, который не упоминается, но тем не менее подразумевается, заключался в классификации геометрических фигур. Это может быть хорошей причиной для того, чтобы рассматривать круг и эллипс как равноправных, не связывать их наследованием и признавать, что они просто имеют одни и те же свойства и НЕ позволять вашему искривлённому ОО-уму иметь дело с этим наблюдением.
источник