Когда вы используете концепцию полиморфизма, вы создаете иерархию классов и, используя родительскую ссылку, вызываете функции интерфейса, не зная, какой конкретный тип имеет объект. Это круто. Пример:
У вас есть коллекция животных, и вы вызываете все функции животных, eat
и вам все равно, едят ли вы собаку или кошку. Но в той же иерархии классов у вас есть животные, у которых есть дополнительные - кроме унаследованных и реализованных из класса Animal
, например makeEggs
, getBackFromTheFreezedState
и так далее. Поэтому в некоторых случаях в вашей функции вы можете захотеть узнать конкретный тип для вызова дополнительных поведений.
Например, если это утреннее время, и если это просто животное, тогда вы звоните eat
, в противном случае, если это человек, то сначала позвоните washHands
, getDressed
а только потом позвоните eat
. Как справиться с этим делом? Полиморфизм умирает. Вам нужно выяснить тип объекта, который звучит как запах кода. Есть ли общий подход для решения этих случаев?
Eater
интерфейс с помощьюeat()
метода, то как клиент вы не заботитесь о том, что егоHuman
реализация должна сначала вызывать,washHands()
иgetDressed()
это детали реализации этого класса. Если, как клиент, вы заботитесь об этом факте, скорее всего, вы не используете правильный инструмент для этой работы.getDressed
нихeat
, это не относится к обеду. В зависимости от ваших обстоятельств,washHands();if !dressed then getDressed();[code to actually eat]
может быть лучшим способом реализовать это для человека. Другая возможность, что если другие вещи требуютwashHands
и / илиgetDressed
называются? Предположим, у вас естьleaveForWork
? Возможно, вам придется структурировать поток вашей программы так, чтобы она вызывалась задолго до этого.Ответы:
Зависит. К сожалению, нет общего решения. Подумайте о своих требованиях и попытайтесь выяснить, что эти вещи должны делать.
Например, вы сказали, что утром разные животные делают разные вещи. Как насчет вас ввести способ
getUp()
илиprepareForDay()
или что - то подобное. Затем вы можете продолжить полиморфизм и позволить каждому животному выполнять свою утреннюю рутину.Если вы хотите различать животных, то не следует хранить их без разбора в списке.
Если больше ничего не работает, то вы можете попробовать шаблон посетителя , который является своего рода хаком для динамической диспетчеризации, где вы можете отправить посетителя, который будет получать точные обратные вызовы от животных. Я хотел бы подчеркнуть, однако, что это должно быть последним средством, если все остальное терпит неудачу.
источник
Это хороший вопрос, и многие люди пытаются понять, как использовать ОО. Я думаю, что большинство разработчиков борются с этим. Я бы хотел сказать, что большинство из них пройдет, но я не уверен, что это так. Большинство разработчиков, по моему опыту, в конечном итоге используют пакеты псевдо-OO-свойствами .
Во-первых, позвольте мне быть ясным. Это не ваша вина. То, как ОО обычно преподают, очень ошибочно.
Animal
Пример является главным виновным, ИМ. В основном, мы говорим, давайте поговорим об объектах, что они могут сделать.Animal
Можетeat()
и это можетspeak()
. Супер. Теперь создайте некоторых животных и напишите, как они едят и говорят. Теперь ты знаешь ОО, верно?Проблема в том, что это идет в ОО с неправильного направления. Почему в этой программе есть животные и почему они должны говорить и есть?
Мне трудно думать о реальном использовании
Animal
типа. Я уверен, что это существует, но давайте обсудим кое-что, о чем я думаю, легче думать: моделирование трафика. Предположим, мы хотим смоделировать трафик в различных сценариях. Вот некоторые основные вещи, которые мы должны сделать, чтобы это сделать.Мы можем углубиться во всевозможные пешеходы и поезда, но мы будем простыми.
Давайте рассмотрим
Vehicle
. Какие возможности нужны автомобилю? Нужно путешествовать по дороге. Нужно уметь останавливаться на сигналах. Нужно уметь ориентироваться на перекрестках.Это, вероятно, слишком просто, но это начало. Сейчас. А как насчет других вещей, которые может делать транспортное средство? Они могут свернуть с дороги и в кювет. Это часть симуляции? Нет, это не нужно У некоторых автомобилей и автобусов есть гидравлика, которая позволяет им подпрыгивать или становиться на колени соответственно. Это часть симуляции? Нет, это не нужно Большинство автомобилей сжигают бензин. Некоторые нет. Является ли силовая установка частью симуляции? Нет, это не нужно Размер колеса? Не нужно это GPS навигация? Информационно-развлекательная система? Не нужно им.
Вам нужно только определить поведение, которое вы собираетесь использовать. В связи с этим, я думаю, что часто лучше создавать ОО-интерфейсы из кода, который взаимодействует с ними. Вы начинаете с пустого интерфейса, а затем начинаете писать код, который вызывает несуществующие методы. Вот как вы знаете, какие методы вам нужны в вашем интерфейсе. Затем, как только вы это сделаете, вы начнете определять классы, которые реализуют это поведение. Поведение, которое не используется, не имеет значения и не требует определения.
Весь смысл OO состоит в том, что вы можете добавить новые реализации этих интерфейсов позже, не изменяя вызывающий код. Единственный способ, который работает, - это если потребности вызывающего кода определяют, что происходит в интерфейсе. Невозможно определить все варианты поведения всех возможных вещей, которые можно придумать позже.
источник
TL; DR:
Подумайте об абстракции и методах, которые применяются ко всем подклассам и охватывают все, что вам нужно.
Давайте сначала остаться с вашим
eat()
примере.Это свойство быть человеком, что в качестве предпосылки к еде люди хотят мыть руки и одеваться перед едой. Если вы хотите, чтобы кто-то пришел к вам, чтобы позавтракать с вами, не говорите им, чтобы они вымыли руки и оделись, они делают это самостоятельно, когда вы приглашаете их, или они отвечают: «Нет, я не могу прийти Я не вымыла руки и еще не оделась ».
Вернуться к программному обеспечению:
Поскольку
Human
экземпляр не будет есть без предварительных условий, я бы сделал методHuman
's'eat()
,washHands()
иgetDressed()
если это не было сделано. Это не должно быть вашей работой какeat()
знать, звонить, об этой особенности. Альтернативой упрямому человеку было бы выбрасывать исключение («Я не готов есть!»), Если предварительные условия не выполняются, оставляя вас разочарованными, но, по крайней мере, информированными о том, что еда не работает.Как насчет
makeEggs()
?Я бы порекомендовал изменить ваше мышление. Вы, вероятно, хотите выполнить запланированные утренние обязанности всех существ. Опять же, как звонящий, ваша работа не должна знать, каковы их обязанности. Поэтому я бы рекомендовал
doMorningDuties()
метод, который реализуют все классы.источник
Ответ довольно прост.
Вам не нужно обращаться с этим, потому что это не будет служить цели. Интерфейс обычно разрабатывается в зависимости от того, как он будет использоваться. Если ваш интерфейс не определяет мытье рук, то вы не заботитесь об этом как о вызывающей стороне интерфейса; если бы вы сделали, вы бы разработали его по-другому.
Например, в псевдокоде:
Теперь вы реализуете
IMorningPerformer
для того,Animal
чтобы просто выполнять прием пищи, а дляHuman
вас также внедряете его, чтобы мыть руки и одеваться. Вызывающий ваш метод MorningTime может не заботиться о том, человек это или животное. Все, что нужно, - это утренняя рутина, которую каждый объект делает превосходно благодаря ОО.Или это?
Почему предполагаем это? Я думаю, что это может быть неправильным предположением.
Да, обычно это решается с помощью тщательно разработанной иерархии классов или интерфейсов. Обратите внимание, что в приведенном выше примере нет ничего, что противоречило бы вашему примеру в том виде, как вы его дали, однако, вы, вероятно, будете чувствовать себя неудовлетворенным, потому что вы сделали еще несколько предположений, которые вы не написали в вопросе на момент написания и эти предположения, вероятно, нарушены.
Вы можете пойти к кроличьей норе, если ужесточите свои предположения, а я внесу изменения в ответ, чтобы все же удовлетворить их, но я не думаю, что это было бы полезно.
Проектирование хороших иерархий классов является сложным и требует глубокого понимания вашей бизнес-сферы. Для сложных доменов каждый проходит две, три или даже больше итераций, поскольку они уточняют свое понимание того, как взаимодействуют различные объекты в своей бизнес-области, пока не придут к адекватной модели.
Вот где отсутствуют упрощенные примеры с животными. Мы хотим научить простому, но проблема, которую мы пытаемся решить, не очевидна, пока вы не углубитесь, то есть в более сложные соображения и области.
источник