среда, 25 июля 2007 г.

Перевод заметки "Prototype Based Object-Oriented Programming"

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

Основанные на прототипах ОО методы концептуально проще, чем основанные на
классах ОО, но и являются более мощными.


Основанное на прототипах программирование - Wikipedia
Прототипно-ориентированное, или чаще: основанное на прототипах
программирование, - это особый стиль объектно-ориентированного
программирования. Первым примером языка основанного на прототипах был язык
Self, наработки которого затем были скопированны в других проектах,
таких как, языки программирования Cecil, JavaScript, NewtonScript, Io и MOO.

Традиционные ОО

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

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

Для примера, скажем, вы делаете приложение-записную книжку, которое сможет
звонить людям. Вы должны иметь класс "Человек" для хранения списка людей.
Люди имеют имена и телефонный номер. Если вы посмотрите на такую программу, то
найдете, что ваш "Человек" представлен блоком памяти с кодом для дозвона по
телефону и различные экземпляры(Боб, Мария и т.д.) являются блоками памяти с именами
и телефонами с указателями на их класс. Когда вы говорите системе
позвонить Бобу, то она посмотрт телефон Боба из данных экземпляра и затем
обратится по указателю к методу дозвона в классе "Человек".

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

Было бы проще, если бы ваша программа могла изменить описание этих низлежащих
классов, но в большинстве систем они находятся в скомпилированном коде,
что не позволят их изменить.

Прототипные

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

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

Фактически новый объект, в большинстве своем, пустой. Он только тогда начинает
расти в памяти, когда программа менят его. Это совершенно отлично от
традиционных ОО систем, где каждый экземпляр класса всегда резервирует
известное количесво памяти. Здест базовый объект состоит только из
одного указателя.

Дополниетльный данные могут быть добавлены в объект в любое время. Если вы
хотите, чтоб ваш новый "Человек" имел имя "Боб", то вам нужно только добавить
его. Объект, начиная с этого действия, начнёт расти для сохранения
требуемых данных.

Есть одно очень важное различее с обычными языками. Объект увеличивается только
тогда, когда необходимо добавление чего-либо в объект. Хотите, чтоб объект
"Боб" имел номер сотового телефона? Сделайте это. Мари имеет номер факса?
Отлично. Фактически каждый объект такой системы стремится стать отличным от
других, не только данными, но и тем как данные в него были записаны.

Также важно рассмотреть то, что правило "добавить что-то" применимо и к методам.
Если объект "Мари" нуждается в методе, котрый никто не имеет, скажем "послать факс",
то вы можете добавить его используя такую же методолгоию. Вот почему многие основанные на
прототипах языки описывают и данные и методы, как "слоты".

Основынные на прототипах языки стремятся начинать с выбора базовых объектов,
которые затем вы сможете копировать. В основном эти объекты имеют тенденцию иметь
только описание методов, полагая, что прграммист добавит нужные данные.
Для примера, объект "Точка", который может помнить координаты на экране, так
же может содержать методы для добавления и стирания точек, но он не будет
содержать значения X и Y, их добавит программист индивидуально для каждой копииобъекта.

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

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


Copyright © 1996-2007 by Dr. Nikolai Bezroukov.

вторник, 24 июля 2007 г.

MVC Web-приложения vs. Web публикация БД

Web-приложения часто рассматриваются, как публикация содержимого базы данных.
Т.е. происходит по схеме:

1) Получить запрос клиента на информацию
2) Составить запрос к БД
3) "Обернуть" ответ в HTML и послать клиенту.


Широко используется процедурный подход: пишутся функции под часто используемые
нужды и т.п.


Можно работать в ООП-стиле: разработать набор классов, отвечающих за
разнообразный функционал: анализатор запросов, генератор SQL-запросов,
обработчик шаблонов и т.п.

В определённый момент развития системы, встаёт вопрос не только разделения
логики от представления, но и применения более многоуровневой архитектуры.
Самая популярная и хорошо себя зарекомендававшая архитектура - это
Модель-Вид-Контроллер(Model-View-Controller) - MVC.
MVC подразумевает создание модели предметной области, т.е.
иерархии классов, соответсвующих реальным обьектам проблемной области.
Т.е. применение ООП.

Представим, что у нас есть система обмена сообщений, что-то типа форума.
Есть пользователи и сообщения. То есть в БД 2 сущности: users, messages
(см. рисунок с ER).

Например, нужно показать сообщение с ID равным "1". В случае публикации БД:
даём запрос по двум таблицам:
SELECT subject, text, user.name, user.surname FROM message
LEFT JOIN user ON message.fk1_login=user.login WHERE message.id=1';
2) Полученный результат в HTML и дело сделано.

В случае с моделью(см. рисунок с диаграммой классов):
1) Создаём экземляр класса сообщения с идентификтором "1"
2) Создаём экземпляр класса пользователя, используя свойство объекта
сообщения

"userLogi_message = new Message(1)
_user = new User(_message.userLogin)n".
Вытаскиваем у объектов _message и _user нужные свойства,
обёртываем в HTML, посылаем клиенту.

При этом при создании экземпляров классов "User" и "Message"
произойдут два запроса(в конструкторах объектов):

1) SELECT subject, text, fk1_login FROM message WHERE id=1;
2) SELECT name, surname, login FROM user WHERE login='soul';

Рисунок 1 - ER-диаграмма

Плюсы и минусы на первый взгляд.

1 случай:
+ высокая скорость(нужен один сложный запрос)
- под каждое представление необходимо формирование своего SQL-запроса

2 случай
+ работаем с объектами модели, а не с БД, что ближе к естественному мышлению
- низкая скорость(происходит несколько простых запросов к БД)


Первый случай, является так называемой публикацией БД в Web,
подходит для небольших задачь.

Второй случай позволяет думать в объектно-ориентированном стиле,
строить более сложные системы.



Рисунок 2 - Диаграмма классов

Добавим в систему возможность объеденения пользователей в группы.
Соотв. в БД появляется сущность "group", а в классовой модели класс "group"
с методами "addUser" и "removeUser" для добавления и удаления
пользователей в группу.

Выводим сообщение c идентификатором "1", а так же
указываем имя, фамилию пользователя и группу, к которой он пренадлежит.

Рисунок 3 - Развитее системы, ER-диагарамма

1. Без объектов модели:
select subject, text, user.name, user.surname, group.name FROM message

LEFT JOIN user ON message.fk1_login=user.login
LEFT JOIN `group` ON user.fk1_group_id=group.id WHERE message.id=1;


2. Через объекты:

_message = new Message(1)
_user = new User(_message.userLogin)
_group = new Group(_user.groupId)


Все нужные нам данные находятся в трёх объектах.

Gри создании экземпляров классов "User", "Group" и "Message"
произойдут три запроса(в конструкторах объектов):

1) SELECT subject, text, fk1_login FROM message WHERE id=1;
2) SELECT name, surname, login FROM user WHERE login='soul';
3) SELECT name FROM `group` WHERE id=1;

Рисунок 4 - Развитее системы, диаграмма классов

Наибольший интерес представляет собой построение самой системы.
На рисунке попытка изобразить из чего состоят разные компоненты системы MVC.

Модель.
Модель содержит в себе так называемую бизнес-логику, то есть логику связанную
с конкретным делом, для которого предназначена программная система.
Логика содержиться в БД(первичные и внешние ключи, триггеры, хранимые процедуры) и
в программных классах, изложенная на каком-либо прикладном языке программирования.

Платформа.
Это может быть созданные разработчиком функции, классы, библиотеки, фреймворки предназнеченные
для решения поставленной задачи согласно выдвинутым требованиям.
Причём разработанная платформа может затем применятся для разработки системы в другой
проблемной области, для которой разрабатывается другая модель.

Рисунок 5 - Архитектура системы

Переход к сервис-ориентированной архитектуре.

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



Рисунок 5 - Сервис-ориентированная архитектура

четверг, 19 июля 2007 г.

Два порта Ruby On Rails на Javascript, для тех, кого не устраивает "R" в RoR

Сотрудник Google Steve Yegge перенёс код фреймворка Ruby on Rails на язык JavaScript.
John Lam на своём сайте сообщает, что Steve Yegge за 6 месяцев сделал
порт RoR, затратив на это 2000 часов.
Steve Yegge хотел использовать RoR в Googe, но Google не хочет увеличивать количиство используемых языков в компании(C++, Java, Python, JavaScript), поэтому Steve принял решение портировать фреймворк на JavaScript - сообщает John Lam.

Это уже второй проект портирования RuR на JavaScript, первым является проект TrimPath Junction сделанный Stive Yen. Проект был начат в 2005 г. и недавно, после большого перерыва, вышла новая версия, в которой серверная часть работает поверх JavaScript фреймворка Helma.