Чем больше я узнаю о различных парадигмах программирования, таких как функциональное программирование, тем больше начинаю сомневаться в разумности таких концепций ООП, как наследование и полиморфизм. Я впервые узнал о наследовании и полиморфизме в школе, и в то время полиморфизм казался прекрасным способом написания универсального кода, который позволял легко расширяться.
Но перед лицом типизации утки (как динамической, так и статической) и функциональных функций, таких как функции высшего порядка, я начал рассматривать наследование и полиморфизм как наложение ненужных ограничений, основанных на хрупком наборе отношений между объектами. Общая идея полиморфизма заключается в том, что вы пишете функцию один раз, а позже вы можете добавить новые функции в вашу программу, не изменяя исходную функцию - все, что вам нужно сделать, - это создать еще один производный класс, который реализует необходимые методы.
Но этого гораздо проще достичь с помощью утилитарной типизации, будь то динамический язык, такой как Python, или статический язык, такой как C ++.
В качестве примера рассмотрим следующую функцию Python, за которой следует ее статический эквивалент C ++:
def foo(obj):
obj.doSomething()
template <class Obj>
void foo(Obj& obj)
{
obj.doSomething();
}
Эквивалент ООП будет выглядеть примерно так:
public void foo(DoSomethingable obj)
{
obj.doSomething();
}
Основное различие, конечно, заключается в том, что версия Java требует создания интерфейса или иерархии наследования, прежде чем она заработает. Таким образом, версия Java требует больше работы и является менее гибкой. Кроме того, я считаю, что большинство реальных иерархий наследования несколько нестабильны. Мы все видели надуманные примеры фигур и животных, но в реальном мире, когда меняются бизнес-требования и добавляются новые функции, трудно выполнить какую-либо работу, прежде чем вы действительно захотите расширить отношения «есть» между подклассы, или переделать / реорганизовать вашу иерархию, чтобы включить дополнительные базовые классы или интерфейсы для соответствия новым требованиям. С типизацией утки вам не нужно беспокоиться о моделировании чего-либо - вы просто беспокоитесь о функциональности, которая вам нужна.
Тем не менее наследование и полиморфизм настолько популярны, что я сомневаюсь, что было бы большим преувеличением назвать их доминирующей стратегией для расширяемости и повторного использования кода. Так почему наследование и полиморфизм так безумно успешны? Я пропускаю некоторые серьезные преимущества, которые наследование / полиморфизм имеют по сравнению с типизацией утки?
источник
obj
нетdoSomething
метода? Возникает ли исключение? Ничего не происходит?Ответы:
Я в основном согласен с тобой, но ради забавы я сыграю в «Адвокат дьявола». Явные интерфейсы дают единственное место для поиска явно, формально указанного контракта, сообщающего вам, что тип должен делать. Это может быть важно, когда вы не единственный разработчик проекта.
Кроме того, эти явные интерфейсы могут быть реализованы более эффективно, чем типизация утиных команд. Вызов виртуальной функции имеет чуть больше накладных расходов, чем обычный вызов функции, за исключением того, что он не может быть встроенным. Утиная печать имеет значительные накладные расходы. Структурная типизация в стиле C ++ (с использованием шаблонов) может генерировать огромное количество раздувания объектного файла (поскольку каждое создание экземпляров не зависит от уровня объектного файла) и не работает, когда вам нужен полиморфизм во время выполнения, а не во время компиляции.
Итог: я согласен с тем, что наследование и полиморфизм в стиле Java могут быть PITA, и альтернативы следует использовать чаще, но он все же имеет свои преимущества.
источник
Наследование и полиморфизм широко используются, потому что они работают для определенных видов задач программирования.
Дело не в том, что их широко преподают в школах, а наоборот: их широко преподают в школах, потому что люди (то есть рынок) обнаружили, что они работают лучше, чем старые инструменты, и поэтому школы начали их учить. [Анекдот: когда я впервые изучал ООП, было чрезвычайно трудно найти колледж, который преподавал бы любой язык ООП. Десять лет спустя было трудно найти колледж, который не преподавал бы язык ООП.]
Вы сказали:
Я говорю:
Нет не
То, что вы описываете, это не полиморфизм, а наследование. Не удивительно, что у вас проблемы с ООП! ;-)
Сделайте резервную копию шага: полиморфизм является преимуществом передачи сообщений; это просто означает, что каждый объект может ответить на сообщение по-своему.
Итак ... Duck Typing - это (или, скорее, позволяет) полиморфизм
Похоже, суть вашего вопроса не в том, что вы не понимаете ООП или что вам это не нравится, а в том, что вам не нравится определять интерфейсы . Это нормально, и если вы будете осторожны, все будет хорошо. Недостатком является то, что если вы допустили ошибку - например, пропустили метод - вы не узнаете об этом до времени выполнения.
Это статическая и динамическая вещь, такая же старая, как Лисп, и не ограниченная ООП.
источник
Почему?
Наследование (с типом утки или без него) обеспечивает повторное использование общей функции. Если это распространено, вы можете убедиться, что оно последовательно используется в подклассах.
Это все. Там нет "ненужных ограничений". Это упрощение.
Аналогично, полиморфизм - это то, что означает «типирование утки». Те же методы. Много классов с идентичным интерфейсом, но разные реализации.
Это не ограничение. Это упрощение.
источник
Наследование - это злоупотребление, как и утка. И то и другое может привести к проблемам.
При строгой типизации вы получаете много «модульных тестов» во время компиляции. При наборе утки вам часто приходится их писать.
источник
Хорошая вещь об изучении вещей в школе является то , что вы делаете изучить их. Не очень хорошая вещь, вы можете принять их слишком догматично, не понимая, когда они полезны, а когда нет.
Затем, если вы выучили это догматически, вы можете позже «бунтовать» так же догматично в другом направлении. Это тоже не хорошо.
Как и с любыми подобными идеями, лучше всего придерживаться прагматичного подхода. Развивайте понимание того, где они подходят, а где нет. И игнорируйте все способы, которыми они были перепроданы.
источник
Да, статическая типизация и интерфейсы являются ограничениями. Но все, с тех пор как было изобретено структурированное программирование (то есть «Goto считается вредным»), было нас ограничивать. Дядя Боб отлично это оценил в своем видео-блоге .
Теперь можно утверждать, что сужение - это плохо, но с другой стороны, оно приносит порядок, контроль и знакомство с очень сложной темой.
Ослабление ограничений за счет (повторного) введения динамической типизации и даже прямого доступа к памяти является очень мощной концепцией, но она также может усложнить работу многих программистов. Особенно программисты привыкли полагаться на компилятор и безопасность типов для большей части своей работы.
источник
Наследование - это очень прочные отношения между двумя классами. Я не думаю, что у Java есть что-то более сильное. Поэтому вы должны использовать его только тогда, когда имеете в виду. Публичное наследование - это отношения «есть», а не «обычно есть». Это действительно, очень легко злоупотреблять наследованием и запутаться в беспорядке. Во многих случаях наследование используется для представления «имеет-а» или «берет-функциональность-от-а», и это обычно лучше сделать по составу.
Полиморфизм является прямым следствием отношений «есть». Если Derived наследует от Base, то каждая Derived «является-a» Base, и, следовательно, вы можете использовать Derived везде, где вы используете Base. Если это не имеет смысла в иерархии наследования, тогда иерархия неверна и, вероятно, происходит слишком много наследования.
Утиная печать - отличная особенность, но компилятор не предупредит вас, если вы собираетесь ее использовать неправильно. Если вы не хотите обрабатывать исключения во время выполнения, вы должны быть уверены, что каждый раз получаете правильные результаты. Может быть проще просто определить статическую иерархию наследования.
Я не большой поклонник статической типизации (я считаю, что это часто является формой преждевременной оптимизации), но она устраняет некоторые классы ошибок, и многие считают, что эти классы стоит устранить.
Если вам нравится динамическая типизация и тип утиной, лучше, чем статическая типизация и определенные иерархии наследования, это нормально. Однако способ Java имеет свои преимущества.
источник
Я заметил, что чем больше я использую замыканий в C #, тем меньше я работаю с традиционными ООП. Раньше наследование было единственным способом легко делиться реализацией, поэтому я думаю, что оно часто использовалось слишком часто, и границы концепции были слишком сильно раздвинуты.
Хотя обычно вы можете использовать замыкания для выполнения большей части того, что вы делаете с наследованием, оно также может быть уродливым.
По сути, это подходящее для работы положение: традиционный ООП может работать очень хорошо, когда у вас есть подходящая модель, а замыкания могут работать очень хорошо, когда вы этого не делаете.
источник
Истина лежит где-то посередине. Мне нравится, как C # 4.0, будучи статически типизированным языком, поддерживает "типизацию утки" по ключевому слову "dynamic"
источник
Наследование, даже когда разум с точки зрения FP, является отличной концепцией; это не только экономит много времени, но и придает смысл отношениям между определенными объектами в вашей программе.
Здесь класс
GoldenRetriever
имеет то же самое,Sound
что иDog
бесплатное спасибо за наследование.Я напишу тот же пример с моим уровнем Haskell, чтобы вы увидели разницу
Здесь вы не избежите необходимости указывать
sound
дляGoldenRetriever
. В общем, проще всего было быно просто Imagen, если у вас есть 20 функций! Если есть эксперт по Haskell, пожалуйста, покажите нам более простой способ.
Тем не менее, было бы здорово иметь сопоставление с образцом и наследование одновременно, когда функция по умолчанию будет использовать базовый класс, если текущий экземпляр не имеет реализации.
источник
Animal
это анти-учебник ООП.