Из Википедии, бесплатной энциклопедии
Перейти к навигации Перейти к поиску

Программирование на основе прототипов - это стиль объектно-ориентированного программирования, в котором повторное использование поведения (известное как наследование ) выполняется посредством процесса повторного использования существующих объектов, которые служат прототипами . Эта модель также может быть известна как прототипное , прототипно-ориентированное, бесклассовое или основанное на экземплярах программирование.

В программировании на основе прототипов используются обобщенные объекты, которые затем можно клонировать и расширять. Используя фрукт в качестве примера, объект «фрукт» будет представлять свойства и функциональность фруктов в целом. Объект «банан» будет клонирован из объекта «фрукт», а общие свойства, характерные для бананов, будут добавлены. Каждый отдельный объект «банан» будет клонирован из универсального объекта «банан». Сравните с парадигмой, основанной на классах , где класс «фрукт» будет расширен классом «банан» .

Первым прототипно-ориентированным языком программирования был Self , разработанный Дэвидом Ангаром и Рэндаллом Смитом в середине 1980-х годов для исследования тем в области объектно-ориентированного проектирования языков. С конца 1990-х годов бесклассовая парадигма становится все более популярной. Некоторые современные прототипы-ориентированных языков JavaScript (и другие ECMAScript реализации , такие как JScript и Flash , «ы ActionScript 1.0), Lua , Сесил , NewtonScript , Ио , Ioke , МОО , REBOLи AHK .

Дизайн и реализация [ править ]

Прототипное наследование в JavaScript описывается Дугласом Крокфордом как:

Вы создаете объекты-прототипы, а затем ... создаете новые экземпляры. Объекты изменяемы в JavaScript, поэтому мы можем дополнять новые экземпляры, давая им новые поля и методы. Затем они могут выступать в качестве прототипов даже для более новых объектов. Нам не нужны классы, чтобы создавать множество похожих объектов… Объекты наследуются от объектов. Что может быть более объектно-ориентированным, чем это? [1]

Сторонники программирования на основе прототипов утверждают, что оно побуждает программиста сосредоточиться на поведении некоторого набора примеров и только позже беспокоиться о классификации этих объектов на архетипические объекты, которые позже используются аналогично классам . [2] Многие системы на основе прототипов поощряют изменение прототипов во время выполнения , в то время как только очень немногие объектно-ориентированные системы на основе классов (например, динамическая объектно-ориентированная система, Common Lisp , Dylan , Objective-C , Perl , Python , Ruby или Smalltalk ) позволяют изменять классы во время выполнения программы.

Почти все системы на основе прототипов основаны на интерпретируемых и динамически типизированных языках. Однако системы, основанные на статически типизированных языках, технически осуществимы. Язык Omega, обсуждаемый в Prototype-Based Programming [3], является примером такой системы, хотя, согласно веб-сайту Omega, даже Omega не является исключительно статическим, а его «компилятор может использовать статическое связывание там, где это возможно, и может улучшить эффективность программы ".

Строительство объекта [ править ]

В языках, основанных на прототипах, нет явных классов. Объекты наследуются напрямую от других объектов через свойство прототипа. Свойство прототипа называется прототипом в Self и JavaScript или прототипом в Io . Есть два метода создания новых объектов: создание объекта ex nihilo («из ничего») или путем клонирования существующего объекта. Первый поддерживается посредством некоторой формы литерала объекта , объявлений, в которых объекты могут быть определены во время выполнения с помощью специального синтаксиса, такого как {...}, и переданы непосредственно в переменную. Хотя большинство систем поддерживают различные варианты клонирования, ex nihiloсоздание объекта не так заметно. [4]

В языках, основанных на классах, новый экземпляр создается с помощью функции конструктора класса , специальной функции, которая резервирует блок памяти для членов объекта (свойств и методов) и возвращает ссылку на этот блок. Необязательный набор аргументов конструктора может быть передан функции и обычно хранится в свойствах. Результирующий экземпляр унаследует все методы и свойства, определенные в классе, который действует как своего рода шаблон, на основе которого могут быть созданы объекты с аналогичным типом.

Системы, поддерживающие создание объектов ex nihilo, позволяют создавать новые объекты с нуля без клонирования существующего прототипа. Такие системы предоставляют специальный синтаксис для определения свойств и поведения новых объектов без ссылки на существующие объекты. Во многих языках прототипов существует корневой объект, часто называемый Object , который устанавливается в качестве прототипа по умолчанию для всех других объектов, созданных во время выполнения, и который несет обычно необходимые методы, такие как функция toString () для возврата описания объекта. в виде строки. Одним из полезных аспектов создания объекта ex nihilo является обеспечение того, чтобы имена слотов (свойств и методов) нового объекта не имели пространства имен.конфликты с верхним уровнем объекта объектом. (В языке JavaScript это можно сделать, используя нулевой прототип, то есть Object.create (null) .)

Клонирование относится к процессу создания нового объекта путем копирования поведения существующего объекта (его прототипа). Таким образом, новый объект несет в себе все качества оригинала. С этого момента новый объект может быть изменен. В некоторых системах результирующий дочерний объект поддерживает явную связь (через делегирование или сходство ) со своим прототипом, и изменения в прототипе вызывают соответствующие изменения, которые становятся очевидными в его клоне. Другие системы, такие как Forth- подобный язык программирования Kevo , не распространяют изменения из прототипа таким образом, а вместо этого следуют более конкатенативной модели, в которой изменения в клонированных объектах не распространяются автоматически по потомкам.[2]

// Пример истинного прототипного стиля наследования // в JavaScript.// создание объекта с использованием буквального // обозначения объекта {}. var  foo  =  { имя :  "foo" ,  один :  1 ,  два :  2 };// Другой объект. var  bar  =  { two :  "два" ,  three :  3 };// Object.setPrototypeOf () - это метод, представленный в ECMAScript 2015. // Для простоты давайте представим, // что следующая строка работает независимо от // используемого движка: Object . setPrototypeOf ( bar ,  foo );  // foo теперь является прототипом bar.// Если с этого момента мы попытаемся получить доступ к свойствам foo из bar //, у нас все получится. бар . one  // принимает значение 1.// Свойства дочернего объекта также доступны. бар . three  // Решается на 3.// Собственная панель свойств теневого прототипа . два ;  // Преобразуется в бар "два" . имя ;  // не затрагивается, разрешается в "foo" foo . имя ;  // Преобразуется в "foo"

Этот пример в JS 1.8.5+ (см. Https://kangax.github.com/es5-compat-table/ )

var  foo  =  { один :  1 ,  два :  2 };// бар. [[прототип]] = foo var  bar  =  Object . создать ( foo );бар . три  =  3 ;бар . один ;  // 1 бар . два ;  // 2 бара . три ;  // 3

Делегирование [ править ]

В языках на основе прототипов, использующих делегирование , среда выполнения языка может отправлятьправильный метод или поиск нужного фрагмента данных, просто следуя серии указателей делегирования (от объекта к его прототипу), пока не будет найдено совпадение. Все, что требуется для установления этого разделения поведения между объектами, - это указатель делегирования. В отличие от отношений между классом и экземпляром в объектно-ориентированных языках на основе классов, взаимосвязь между прототипом и его ответвлениями не требует, чтобы дочерний объект имел память или структурное сходство с прототипом за пределами этой ссылки. Таким образом, дочерний объект может продолжать изменяться и исправляться с течением времени без изменения структуры связанного с ним прототипа, как в системах на основе классов. Также важно отметить, что не только данные, но и методы могут быть добавлены или изменены. По этой причине,в некоторых языках, основанных на прототипах, данные и методы называются «слотами» или «членами».[ необходима цитата ]

Конкатенация [ править ]

В конкатенативном прототипировании - подходе, реализованном в языке программирования Kevo - нет видимых указателей или ссылок на исходный прототип, из которого клонируется объект. Объект-прототип (родительский) копируется, а не связывается, и делегирования нет. В результате изменения прототипа не будут отражены в клонированных объектах. [5]

Основное концептуальное отличие этой схемы заключается в том, что изменения, внесенные в объект-прототип, не распространяются автоматически на клоны. Это можно рассматривать как преимущество или недостаток. (Тем не менее, Kevo предоставляет дополнительные примитивы для публикации изменений в наборах объектов на основе их сходства - так называемые семейные сходства или механизм семейства клонов [5]- а не через таксономическое происхождение, как это типично для модели делегирования.) Также иногда утверждается, что прототипирование на основе делегирования имеет дополнительный недостаток, заключающийся в том, что изменения дочернего объекта могут повлиять на последующие операции родительского объекта. Однако эта проблема не присуща модели, основанной на делегировании, и не существует в языках, основанных на делегировании, таких как JavaScript, которые гарантируют, что изменения дочернего объекта всегда записываются в самом дочернем объекте, а не в родительских (т.е. value затеняет родительское значение, а не изменяет родительское значение).

В упрощенных реализациях конкатенативное прототипирование будет иметь более быстрый поиск членов, чем прототипирование на основе делегирования (потому что нет необходимости следовать цепочке родительских объектов), но, наоборот, будет использовать больше памяти (потому что все слоты копируются, а не существует единственная слот, указывающий на родительский объект). Однако более сложные реализации могут избежать этой проблемы, хотя требуется компромисс между скоростью и памятью. Например, системы с конкатенативным прототипированием могут использовать реализацию копирования при записи, чтобы обеспечить обмен данными за кулисами - и такой подход действительно следует Kevo. [6] И наоборот, системы с прототипированием на основе делегирования могут использовать кэширование для ускорения поиска данных.

Критика [ править ]

Сторонники объектных моделей на основе классов, которые критикуют системы на основе прототипов, часто имеют проблемы, аналогичные опасениям, которые сторонники систем статических типов для языков программирования имеют в отношении систем динамических типов (см . Тип данных ). Обычно такие проблемы включают: правильность , безопасность , предсказуемость , эффективность и незнание программиста.

По первым трем пунктам классы часто рассматриваются как аналогичные типам (в большинстве статически типизированных объектно-ориентированных языков они выполняют эту роль), и предлагается предоставить своим экземплярам и пользователям их экземпляров договорные гарантии того, что они будут вести себя. каким-то образом.

Что касается эффективности, объявление классов упрощает многие оптимизации компилятора, которые позволяют разработать эффективный метод и поиск переменных экземпляра. Для языка Self много времени было потрачено на разработку, компиляцию и интерпретацию методов для повышения производительности систем на основе прототипов по сравнению с системами на основе классов.

Общая критика языков, основанных на прототипах, заключается в том, что сообщество разработчиков программного обеспечения не знакомо с ними, несмотря на популярность и проникновение на рынок JavaScript . Этот уровень знаний о системах, основанных на прототипах, кажется, растет с распространением фреймворков JavaScript и комплексным использованием JavaScript по мере развития Интернета . [7] [ необходима цитата ] ECMAScript 6 представил классы как синтаксический сахар по сравнению с существующим наследованием на основе прототипов JavaScript, предоставив альтернативный способ создания объектов и работы с наследованием. [8]

Языки, поддерживающие программирование на основе прототипов [ править ]

  • Параллельный язык на основе акторов (ABCL): ABCL / 1 , ABCL / R , ABCL / R2 , ABCL / c +
  • Агора
  • AutoHotkey
  • Сесил и Дизель из Craig Chambers
  • ХолодныйC
  • COLA
  • Common Lisp
  • Голубой
  • ECMAScript
    • ActionScript 1.0, используемый Adobe Flash и Adobe Flex
    • E4X
    • JavaScript
    • JScript
    • Машинопись
  • Ио
  • Иоке
  • Jsonnet
  • Logtalk
  • LPC
  • Lua
  • M2000
  • Клен
  • MOO
  • Неко
  • NewtonScript
  • Nix
  • Объект Лисп
  • Косой
  • Омега
  • OpenLaszlo
  • Perl с модулем Class :: Prototyped
  • Python с prototype.py .
  • R , с пакетом proto
  • REBOL
  • Красный (язык программирования)
  • Себя
  • Сеф
  • Slate (язык программирования)
  • SmartFrog
  • Etoys
  • ТАДС
  • Tcl с расширением snit
  • Умаджин [9]

См. Также [ править ]

  • Программирование на основе классов (контраст)
  • Дифференциальное наследование
  • Парадигма программирования

Ссылки [ править ]

  1. ^ Крокфорд, Дуглас. «Прототипное наследование в JavaScript» . Проверено 20 августа 2013 года .
  2. ^ a b Тайвалсаари, Антеро. «Раздел 1.1». Классы против прототипов: некоторые философские и исторические наблюдения . п. 14. CiteSeerX 10.1.1.56.4713 . 
  3. ^ Блашек, Гюнтер. «Раздел 2.8». Омега: статически типизированные прототипы . п. 177.
  4. ^ Дони, Чистоф; Маленфан, Жак; Барду, Даниэль. «Раздел 1.2» (PDF) . Классификация языков программирования на основе прототипов . п. 17.
  5. ^ a b Антеро Тайвалсаар (2009). «Упрощение JavaScript с помощью наследования прототипов на основе конкатенации» (PDF) . Технологический университет Тампере. Архивировано из оригинала на 2009 . Проверено 11 марта 2015 . Кево реализовал объектную модель на основе чистой конкатенации, в которой новые объекты создавались путем копирования, а пространства имен всех объектов всегда были полностью автономными. … Более того, у Kevo был внутренний механизм семейства клонов, который позволял отслеживать «генеалогию» изменений среди групп объектов, так что изменения отдельных объектов могли быть при необходимости распространены на другие объекты.
  6. ^ Taivalsaari, Антеро (1992). «Kevo, объектно-ориентированный язык программирования, основанный на прототипах, основанный на конкатенации и модульных операциях». Технический отчет LACIR 92-02 . Университет Виктории.
  7. ^ «Прототипное объектно-ориентированное программирование с использованием JavaScript» . Список отдельно . 2016-04-26 . Проверено 21 октября 2018 .
  8. ^ «Классы» . Ссылка на JavaScript . Сеть разработчиков Mozilla . Проверено 9 февраля +2016 .
  9. ^ Собственный язык сценариев. http://www.davidbrebner.com/?p=4 содержит несколько основных примеров использования.

Дальнейшее чтение [ править ]

  • Абади, Мартин ; Лука Карделли (1996). Теория объектов . Springer-Verlag. ISBN 978-1-4612-6445-3.
  • Классовая война: классы против прототипов , Брайан Фут.
  • Благородный, Джеймс; Тайвалсаари, Антеро; Мур, Иван, ред. (1999). Программирование на основе прототипов: концепции, языки и приложения . Springer-Verlag. ISBN 981-4021-25-3.
  • Использование прототипов объектов для реализации общего поведения в объектно-ориентированных системах , Генри Либерман, 1986.