Прототипная объектная ориентация (Rating: +6)
Предыстория
Приветствую. Я уже не раз говорил, что язык JS я считаю если не самым любимым, то как минимум вторым (после C++). Это связано с тем, что благодаря этому, казалось бы, сложному языку, я постиг один из "дзенов" программирования, а именно великую парадигму прототипной ориентации объектно-ориентированного языка. Многие программисты, не знакомые с этим, не побоюсь этого слова, чистой реализацией, считают ее более сложной и даже не объектной, но на самом деле это не так, скорее наоборот, классическая объектная ориентация оказывается всего лишь надстройкой "сахара" над этой парадигмой.
Не так давно, я начал изучать язык скриптов известного редактора Vim, и сразу же обратил внимание на его объектную парадигму, и занесло...
Объекты в Vim
Забегая вперед скажу, что в этой статье речь пойдет о реализации прототипной ориентации в Vim(!), но все попорядку.
В Vim объекты создаются и используются следующим образом (" в Vim это начало строки комментария):
Что мы видим из стандартного синтаксиса Vim?
* Классы не используются вообще, то есть нет возможности заранее определить структуру будущего объекта, его свойства и методы, объекты создаются сразу перечислением всех свойств и методов, а затем к ним добавляются методы.
* Нет возможности наследовать поведение, то есть мы не можем создать объект основываясь на структуре другого объекта, нужно явно копировать в новый объект все свойства и методы родителя.
* Снижается повторное использование кода, за счет отсутствия наследования, то есть возможности выносить логику в родительские объекты.
Этот список можно продолжать еще долго, но это есть то, с чего начинается любой объектно-ориентированный язык программирования - ассоциативный массив с возможностью передачи функций в качестве его элементов.
Как из всего этого сделать прототипную модель? Достаточно реализовать всего один метод!
Прототипирование
Сначала немного теории. Чтобы существующая в Vim объектная модель могла хоть немного походить на прототипную, достаточно реализовать возможность наследования реализации. В прототипной модели делается это довольно просто, но чтобы понять это, необходимо забыть о классической реализации объектности в языках программирования. Дело в том, что в прототипной модели нет понятия класса вообще, то есть за класс выступает обычный объект, называемый прототипом. Предположим нам нужно реализовать программу для магазина. Имеем два типа объектов: покупатели и сотрудники. И тот и другой тип объектов по сути является типом "Человек", то есть они отличаются только несколькими дополнительными свойствами и методами, а общие можно вынести в отдельный тип объектов. В качестве типа объектов "Человек" выступает объект, в качестве свойств которого задаются значения по умолчанию. В этот же объект выносятся и все общие методы.
Такой объект называется прототипом, так как на основании его будут создаваться другие типы объектов, а делается это путем создания ссылки на все методы прототипа из дочернего объекта (чтобы не копировать функции), а так же созданием ссылки на сам прототип (чтобы не копировать свойства):
Вот собственно и вся реализация прототипной модели в Vim. С помощью данной функции можно создавать объекты наследуя структуру других объектов (прототипов). Как это использовать:
Реализация
Как вы могли заметить, прототипная модель это всего лишь механизм, позволяющий создавать ссылки между прототипом и объектом так, чтобы вторым было удобно пользоваться. В моем случае, в объекте создаются ссылки на методы прототипа, это позволяет вызывать их прямо из объекта, при этом не забивая память копиями методов. Так же создается свойство parent в объекте, ссылающееся на прототип, это позволяет обращаться к свойствам родителя без их копирования в объект, а так же переопределять методы родителя:
При переопределении метода всегда можно получить доступ к перегружаемому методы через ссылку parent:
Итоги
Никогда не знаешь, сколько интересного можно найти в "стареньком" редакторе. Обязательно изучайте различные реализации давно известных вам решений, это позволяет взглянуть на одни и те же вещи под совершенно разными углами.
Added: Артур
29.01.2014 / 09:20Приветствую. Я уже не раз говорил, что язык JS я считаю если не самым любимым, то как минимум вторым (после C++). Это связано с тем, что благодаря этому, казалось бы, сложному языку, я постиг один из "дзенов" программирования, а именно великую парадигму прототипной ориентации объектно-ориентированного языка. Многие программисты, не знакомые с этим, не побоюсь этого слова, чистой реализацией, считают ее более сложной и даже не объектной, но на самом деле это не так, скорее наоборот, классическая объектная ориентация оказывается всего лишь надстройкой "сахара" над этой парадигмой.
Не так давно, я начал изучать язык скриптов известного редактора Vim, и сразу же обратил внимание на его объектную парадигму, и занесло...
Объекты в Vim
Забегая вперед скажу, что в этой статье речь пойдет о реализации прототипной ориентации в Vim(!), но все попорядку.
В Vim объекты создаются и используются следующим образом (" в Vim это начало строки комментария):
let obj = {'name': 'Artur'} " Создаем объект function! obj.getName() dict " Создаем метод объекта return self.name endfunction echo obj.getName() " Вызываем метод объекта
Что мы видим из стандартного синтаксиса Vim?
* Классы не используются вообще, то есть нет возможности заранее определить структуру будущего объекта, его свойства и методы, объекты создаются сразу перечислением всех свойств и методов, а затем к ним добавляются методы.
* Нет возможности наследовать поведение, то есть мы не можем создать объект основываясь на структуре другого объекта, нужно явно копировать в новый объект все свойства и методы родителя.
* Снижается повторное использование кода, за счет отсутствия наследования, то есть возможности выносить логику в родительские объекты.
Этот список можно продолжать еще долго, но это есть то, с чего начинается любой объектно-ориентированный язык программирования - ассоциативный массив с возможностью передачи функций в качестве его элементов.
Как из всего этого сделать прототипную модель? Достаточно реализовать всего один метод!
Прототипирование
Сначала немного теории. Чтобы существующая в Vim объектная модель могла хоть немного походить на прототипную, достаточно реализовать возможность наследования реализации. В прототипной модели делается это довольно просто, но чтобы понять это, необходимо забыть о классической реализации объектности в языках программирования. Дело в том, что в прототипной модели нет понятия класса вообще, то есть за класс выступает обычный объект, называемый прототипом. Предположим нам нужно реализовать программу для магазина. Имеем два типа объектов: покупатели и сотрудники. И тот и другой тип объектов по сути является типом "Человек", то есть они отличаются только несколькими дополнительными свойствами и методами, а общие можно вынести в отдельный тип объектов. В качестве типа объектов "Человек" выступает объект, в качестве свойств которого задаются значения по умолчанию. В этот же объект выносятся и все общие методы.
let People = {'name': 0} " Прототип Человек function! People.getName() dict return self.name endFunction
Такой объект называется прототипом, так как на основании его будут создаваться другие типы объектов, а делается это путем создания ссылки на все методы прототипа из дочернего объекта (чтобы не копировать функции), а так же созданием ссылки на сам прототип (чтобы не копировать свойства):
" Функция создает объект на основе прототипа. " 4 prototype - прототип. " 4 properties - свойства создаваемого объекта. function! Expand(prototype, properties) let obj = {} " Наследование свойств. " Наследование реализуется путем формирования ссылки на родительский объект в свойстве parent. let obj.parent = a:prototype " Наследование методов. " Наследование реализуется путем формирования ссылок на методы родительского класса в одноименных методах дочернего. for k in keys(a:prototype) " Проход по всем методам прототипа let t = type(a:prototype[k]) if t == 2 let obj[k] = a:prototype[k] " Создание ссылок на методы прототипа из дочернего объекта endif endfor " Формирование свойств. " Реализуется путем копирования переданного списка в создаваемый объект. for [k, v] in items(a:properties) " Формирование частных свойств объекта let t = type(v) if t == 3 || t == 4 let obj[k] = deepcopy(v) else let obj[k] = v endif endfor return obj endfunction
Вот собственно и вся реализация прототипной модели в Vim. С помощью данной функции можно создавать объекты наследуя структуру других объектов (прототипов). Как это использовать:
let s:Object = {} " Корневой прототип function s:Object.getType() dict " Метод прототипа return 'prototype' endfunction " Создание объекта через прототип let s:o1 = Expand(s:Object, {'name': 'Artur'}) function s:o1.getName() dict " Метод объекта return self.name endfunction echo s:o1.getType() " prototype - вызов метода прототипа echo s:o1.getName() " Artur - вызов метода объекта
Реализация
Как вы могли заметить, прототипная модель это всего лишь механизм, позволяющий создавать ссылки между прототипом и объектом так, чтобы вторым было удобно пользоваться. В моем случае, в объекте создаются ссылки на методы прототипа, это позволяет вызывать их прямо из объекта, при этом не забивая память копиями методов. Так же создается свойство parent в объекте, ссылающееся на прототип, это позволяет обращаться к свойствам родителя без их копирования в объект, а так же переопределять методы родителя:
let s:o1 = Expand(s:Object, {'name': 'Artur'}) function s:o1.getType() dict " Переопределение метода return 'object' endfunction echo s:o1.getType() " object - вызов переопределенного метода
При переопределении метода всегда можно получить доступ к перегружаемому методы через ссылку parent:
echo s:o1.parent.getType() " prototype - вызов родительского метода
Итоги
Никогда не знаешь, сколько интересного можно найти в "стареньком" редакторе. Обязательно изучайте различные реализации давно известных вам решений, это позволяет взглянуть на одни и те же вещи под совершенно разными углами.
Rating:
+6
Views: 2355Comments (4) »