Наследование, полиморфизм и инкапсуляция являются тремя наиболее отличительными и важными особенностями ООП, и в наши дни наследование имеет высокую статистику использования. Я изучаю JavaScript, и здесь все говорят, что он имеет прототипное наследование, и люди повсюду говорят, что это что-то сильно отличающееся от классического наследования.
Однако я не могу понять, в чем их отличие с точки зрения практического использования? Другими словами, когда вы определяете базовый класс (прототип), а затем извлекаете из него некоторые подклассы, вы оба получаете доступ к функциональным возможностям вашего базового класса и можете расширять функции в производных классах. Если мы считаем то, что я сказал, предполагаемым результатом наследования, то почему нас должно волновать, используем ли мы прототип или классическую версию?
Чтобы очистить себя больше, я не вижу различий в полезности и моделях использования прототипа и классического наследования. Это приводит к тому, что мне не интересно узнавать, почему они разные, так как они оба приводят к одному и тому же, OOAD. Чем практически (не теоретически) наследование прототипа отличается от классического наследования?
источник
Классическое наследование наследует поведение без какого-либо состояния от родительского класса. Он наследует поведение в момент создания объекта.
Прототип наследования наследует поведение и состояние от родительского объекта. Он наследует поведение и состояние в момент вызова объекта. Когда родительский объект изменяется во время выполнения, это влияет на состояние и поведение дочерних объектов.
«Преимущество» наследования прототипов заключается в том, что вы можете «исправлять» состояние и поведение после создания всех ваших объектов. Например, в среде Ext JS обычно загружаются «переопределения», которые исправляют основные компоненты платформы после ее создания.
источник
class C(object): def m(self, x): return x*2
а затем,instance = C()
когда я бегу,instance.m(3)
я получаю6
. Но если бы я тогда изменитьC
такC.m = lambda s, x: x*x
и я бегуinstance.m(3)
я теперь получить9
. То же самое происходит, если я создаюclass D(C)
и изменяю метод наC
все экземпляры, которые такжеD
получают измененный метод. Я неправильно понимаю или это означает, что Python не имеет классического наследования в соответствии с вашим определением?Во-первых: в большинстве случаев вы будете использовать объекты, а не определять их, и использование объектов одинаково для обеих парадигм.
Второе: в большинстве прототипных сред используется тот же тип разделения, что и в средах на основе классов - изменяемые данные в экземпляре с наследуемыми методами. Так что опять очень мало различий. (См. Мой ответ на этот вопрос о переполнении стека и «Организация самостоятельной работы без классов . Посмотрите на Citeseer для PDF-версии» .)
Третье: динамическая природа Javascript оказывает гораздо большее влияние, чем тип наследования. Тот факт, что я могу добавить новый метод ко всем экземплярам типа, присваивая его базовому объекту, очень удобен, но я могу сделать то же самое в Ruby, открыв класс заново.
В-четвертых: практические различия невелики, в то время как практическая проблема забвения в использовании
new
намного больше - то есть, вы гораздо больше подвержены тому, что пропустите,new
чем вы будете испытывать разницу между прототипом и классическим кодом ,При этом практическое различие между прототипом и классическим наследованием заключается в том, что ваши методы "вещи, которые держат" (классы) совпадают с вашими вещами, которые держат данные (экземпляры). Это означает, что вы можете создавать свои классы по частям, используя все те же инструменты манипулирования объектами, которые вы использовали бы в любом случае. (Это, собственно, то, как это делают все библиотеки эмуляции классов. Для подхода, не совсем похожего на все остальные, посмотрите на Traits.js ). Это в первую очередь интересно, если вы занимаетесь метапрограммированием.
источник
Наследование прототипов в JavaScript отличается от классов следующими важными способами:
Конструкторы - это просто функции, которые вы можете вызывать без
new
:Здесь нет личных переменных или методов, в лучшем случае вы можете сделать это:
В предыдущем примере вы не сможете существенно расширить класс, если вы прибегаете к фиктивным частным переменным и методам, и, кроме того, все объявленные вами публичные методы будут создаваться заново при каждом создании нового экземпляра.
источник
color
,r
,x
,y
иdrawCircle
, привязанных к лексической областиCircle
Circle.call()
как конструктор? Похоже, вы пытаетесь описать «функциональные объекты» (неправильно) ...