Программирование на основе прототипов - Prototype-based programming

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

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

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

Дизайн и реализация

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

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

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

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

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

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

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

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

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

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

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

вар фу = {один: 1, два: 2};// бар. [[прототип]] = fooвар бар = Объект.Создайте(фу);бар.три = 3;бар.один; // 1бар.два; // 2бар.три; // 3

Делегация

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

Конкатенация

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

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

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

Критика

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

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

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

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

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

Смотрите также

Рекомендации

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

дальнейшее чтение