Оберон-технология: особенности и перспективы |
Тематика обсуждения: Оберон-технология. Особенности, перспективы, практическое применение.
Всего в теме 6256 сообщений
Добавить свое сообщение
Отслеживать это обсуждение Обсуждение из раздела Школа ОБЕРОНА
№ 3566 26-03-2007 18:27 | |
Ответ на »сообщение 3565« (AVC)
___________________________
Можно и базывый класс конечно.
А вообще механизм навешивания аспектов чрезвычайно гибок.
Можно например по wildcard то есть по шаблонам имени класа или поля/метода
например
pontcut sql_*.* AspectLogDaabaseActivity
То есть навесить на все классы чьи имена начинаются sql_ и на все их поля и методы, аспект логирующий доступ к базе данных.
За счет чего? Рефлексии?
А нельзя ли тогда за ее счет и обойти этот аспект?
В смысле ? Самому себе подножку поставить ?
Эт вряд ли :)) Разве что вы каким то образом умубритесь переделать правила reflections в системе.
То есть случайно поломать или забыть чо то сделать не получится, даже если очень постараться.
Ну а если специально, и у злоумышленника ТАКОЙ доступ к системе, то там уже неважно аспекты у вас или еще что :))
№ 3565 26-03-2007 18:16 | |
Ответ на »сообщение 3562« (Jack Of Shadows)
___________________________
>>>Ну звездочку там не обязательно ставить. Можно имя конкретного класса. Можно даже список конкретных классов и их полей.
А можно указать полный список всех потомков? :)
Или достаточно указать базовый класс, а потомки "подключатся" автоматически?
>>>Аспекты например вы можете навесить на классы чьих исходников у вас нет.
За счет чего? Рефлексии?
А нельзя ли тогда за ее счет и обойти этот аспект?
№ 3564 26-03-2007 18:07 | |
Ответ на »сообщение 3563« (Илья Ермаков)
___________________________
Прошу прощения, время позднее :-)
Конечно, тип EmpWrapper - он не "просто так", а содержит обернутый Employee:
EmpWrapper = POINTER TO RECORD (Employees.Employee)
emp: Employees.Employee
END,
а EmpDirectory содержит предыдущий (базовый с ее точки зрения) каталог:
EmpDirectory = POINTER TO RECORD (Employees.Directory)
baseDir: Employees.Directory
END
- и в нужные моменты они делегируют свои вызовы базовым версиям...
№ 3563 26-03-2007 18:00 | |
Ответ на »сообщение 3560« (Jack Of Shadows)
___________________________
Кстати... Пораскинув мозгами, понимаю, что проблемка-то и правда из серии надуманных :-) Сначала в мейнстримовском ООП на нее налетели, а потом плодят "припарки", чтобы ее обходить.
Хотя - терминология "аспект" хорошая, как и сама задача раздельной реализации аспектов поведения.
Итак - суть задачи: у нас есть некоторый класс, реализующий основную логику. Нам нужно иметь возможность "снаружи", не трогая его реализации, добавить к его методам какую-то пред/пост-логику, аспект в поведении, при этом прозрачно для всех клиентов.
Фактически, аспект - это "обертка" на базовый класс. И реализовать его можно было бы как класс-обертку, который выполняет аспекты поведения, а затем делегирует вызов обернутому классу. Но - увы, проблема в том, что при этом в стандартной ОО-парадигме клинетский код потребуется переделывать, чтобы он начал работать с оберткой вместо исходного класса... А если аспектов-оберток много - ёёёлки-палки :-)
Что у нас есть? Напишу на Обероне, но так, как принято сразу "лабать" в мейнстриме:
MODULE Employees;
TYPE
Employee* = POINTER TO RECORD ... END;
PROCEDURE (e: Employee) SSN* (): SSN;
BEGIN
...
END SSN;
END Employees.
Итак, быстренько слабали класс, открыли его реализацию для прямого использования/наследования, пользуемся из всех других модулей системы, радуемся. И вдруг нам приспичило добавить в систему поддержку безопасности. Модуль Protect, к примеру. Казалось бы - чего проще: напишем обертку - класс-наследник Protect.Employee, который добавит к базовому Employee необходимый аспект поведения. Увы, увы - добавить-то добавит, но вот сотни модулей системы заставить учитывать нововведенный аспект будет весьма трудно. Во-первых, все они работают прямо с классом Empoyees.Employee. Во-вторых - даже если перепишем-перенаправим код на новую обертку - а если оберток несколько? А если в системе уже наплодились десятки классов - наследников Employye?
Вот он - тупик мейнстримовского ООП. Тупик открытой реализации. Тупик наследования реализации. "Уж сколько раз твердили миру" - скрывайте реализацию, наследуйтесь только по интерфейсам, создавайте объекты только через фабрики, делайте гомогенные иерархии... Не слушаются, а потом требуется новые средства в языке плодить, которые позволят "хакнуть" понавернутые иерархии наследования - и заткнуть в середину перехватчики для реализации аспектов... Для компонентной системы, кстати, это очень опасно - вот уж где полностью бесконтрольное вмешательство одних компонент в другие...
На самом деле аспекты реализуются проще пареной репы. Все получается само собой, как побочный эффект, если следовать, например, концепции каталожных объектов в ББ...
MODULE Employee;
TYPE
Employee* = POINTER TO ABSTRACT RECORD END;
(* абстрактный интерфейс - экспортирован *)
Directory* = POINTER TO ABSTRACT RECORD END;
(* абстрактная фабрика-каталог *)
StdEmployee = POINTER TO RECORD (Employee) ... тут все нутро ... END;
(* базовая реализация - скрыта внутри модуля, снаружи недоступна *)
StdDirectory = POINTER TO RECORD (Directory) END;
(* скрытая фабрика-каталог для реализации по умолчанию *)
VAR
dir-: Directory;
PROCEDURE (e: Employee) SSN* (): SSN, NEW, ABSTRACT;
PROCEDURE (d: Directory) NewEmployee* (): Employee, NEW, ABSTRACT;
PROCEDURE (e: StdEmployee) SSN* (): SSN;
BEGIN
... RETURN чего-то там...
END SSN;
PROCEDURE (d: StdDirectory) NewEmployee (): Employee;
VAR e: StdEmployee;
BEGIN
NEW(e); ...инициализируем e...
RETURN e
END NewEmployee;
PROCEDURE SetDir* (d: Directory);
BEGIN
dir := d
END SetDir;
PROCEDURE Init;
VAR d: StdDirectory;
BEGIN
NEW(d); dir := d
END Init;
BEGIN
Init
END Employees.
Все, немного потрудившись над модулем Employees и проделав дополнительную работу, можем теперь пожинать самые разные плоды.
Клиенты создают новых Employee вызовом Employees.dir.NewEmployees, при этом не знают, какая конкретно реализация Employees и какая реализация dir используется, их дело - знать только абстрактный интерфейс (кстати, к вопросу о старом споре - обойти обязательную инициализацию они тоже не могут. Никак. И без всяких конструкторов).
Поскольку реализация сокрыта, то можем ее очень легко подменять (о чем ранее говорилось) - просто переустановив свой dir вызовом SetDir.
А можем не подменять полностью, а добавить свой аспект. Ту же самую пресловутую защиту...
MODULE Protect;
IMPORT Employees;
TYPE
EmpWrapper = POINTER TO RECORD (Employees.Employee) END;
EmpDirectory = POINTER TO RECORD (Employees.Directory) END;
PROCEDURE (w: EmpWrapper) SSN (): SSN;
BEGIN
... узнали через метамеханизмы, кто нас вызвал или что еще там...
RETURN фильтрованный SSN
END SSN;
PROCEDURE (d: EmpDirectory) NewEmployee (): Employees.Employee;
VAR e: EmpWrapper;
BEGIN
NEW(e); ... RETURN e
END NewEmployee;
PROCEDURE InstallProtection;
VAR ed: EmpDirectory;
BEGIN
NEW(ed); Employees.SetDir(ed)
END InstallProctection;
BEGIN
InstallProtection
END Protect.
Про модуль Protect никто в системе слыхом не слыхивает. Он спокойненько подгружается - и устанавливает свой аспект для Employee и для любых других типов, какие там потребуются.
При этом, замечу, все делается, как и всегда в Оберонах, "на горячую", не то что без переписывания, перкомпиляции, но даже без перезапуска...
№ 3562 26-03-2007 17:46 | |
Ответ на »сообщение 3561« (AVC)
___________________________
Происхождение от общего класса как бы обеспечивает выполнение закона тождества во избежание хитрых софизмов. :)
Ну звездочку там не обязательно ставить. Можно имя конкретного класса. Можно даже список конкретных классов и их полей.
В ББ существуют так называемые методы только-для-реализации (implement-only).
Вот и попались. :)) То есть класс данных ДОЛЖЕН знать о том что его будут проверять, и предоставить соответствующие точки проверки пусть и через implement-only.
А это уже leaking abstractions.
В случае с аспектами классы с данными знать ничего не знают ни о каких SecureSSN и вообще ни о каких правилах доступа, даже просто как о точках подцепления к ним (implement-only)
Аспекты например вы можете навесить на классы чьих исходников у вас нет.
А как быть в вашем случае в обероне, если автор классов не удосужился предоставить точки implement-only? а исходников у вас нет ? Приехали.
Короче задача в любом случае решается. Просто в одном случае легко и просто. А в другом с массой оговорок, условий итд итп.
№ 3561 26-03-2007 17:36 | |
Ответ на »сообщение 3560« (Jack Of Shadows)
___________________________
Теперь понятно.
Спасибо!
Далее, что удобно, так это то что тот же самый аспект будет вызываться и на другом обьекте у которого тоже есть поле SSN, Например Client.SSN
Хотя ни Client ни Employee не наследуют от общего предка.
То-то некто удивится, если в его случае (например, для того же Client) SSN означает совсем другое! :)
Результат: Проверка доступа в классах данных отсутствует.
Проверка доступа в коде вывода информации отсутствует.
Обойти (случайно забыть) это поверку невозможно.
повтороно использовать эту проверку в других обьектах где требуется та же функцинальность - запросто.
Собственно, аналогично.
Единственная разница -- требуется происхождение от общего базового класса.
Что, IMHO, более правильно.
Или есть какой-то непреодолимый закон природы, что SSN всегда имеет один и тот же смысл?
Происхождение от общего класса как бы обеспечивает выполнение закона тождества во избежание хитрых софизмов. :)
Ну а теперь раз "за сценой" прояснилось, поведайте нам как вы сделаете это при помощи оберона.
( Озадаченно.) Да я как бы уже рассказал...
№ 3560 26-03-2007 17:11 | |
Ответ на »сообщение 3559« (AVC)
___________________________
Что означает "за сценой" в предложении
За сценой означает описано в аспекте.
У вас есть класс Employee с множеством полей, одно из которых SSN.
Делаете аспект SecureSSN в котором описываете логику доступа и возвращаемые данные.
acpect SecureSSN
bla bla
...
end
Навешиваете его на поле SSN:
pointcut before *.SSN SecureSSN
То есть перехватывать перед обращением к ЛЮБОМУ (*) обьекту с полем SSN
Все. После этого везде где в коде будет встречаться thisEmployee.SSN аспект будет перехватывать обращение и заменять данные согласно правилам доступа.
Далее, что удобно, так это то что тот же самый аспект будет вызываться и на другом обьекте у которого тоже есть поле SSN, Например Client.SSN
Хотя ни Client ни Employee не наследуют от общего предка.
Результат: Проверка доступа в классах данных отсутствует.
Проверка доступа в коде вывода информации отсутствует.
Обойти (случайно забыть) это поверку невозможно.
повтороно использовать эту проверку в других обьектах где требуется та же функцинальность - запросто.
То есть аспекты, как частный случай функционального программирования, это очень легко и удобно, в сравнении с аналогичными решениями из ООП.
Ну а теперь раз "за сценой" прояснилось, поведайте нам как вы сделаете это при помощи оберона.
№ 3559 26-03-2007 17:01 | |
Ответ на »сообщение 3557« (Jack Of Shadows)
___________________________
ПРИМЕР в студию!
Что вы предлагаете ? Пометить поле SSN как implement only ? И ? Чего вы этим добьетесь ?
Того что программист создаст метод класса, в котором будет проверять доступ пользователя к данным ?
Чем это отличается от способа номер 1, который я уже приводил, то есть забить код проверки доступа прямо в класс, хранящий данные?
Jack, я тоже не понял Ваших объяснений, зачем кипятиться? :)
Что означает "за сценой" в предложении
Просто при каждом обращении к полю SSN, за сценой вызывается функция проверки доступа, которая перехватывает чтение поля, и заменяет данные в соответствии с правами доступа.?
Пока это остается "под ковром" рано, IMHO, говорить о красоте и модульности.
Давайте будет потихоньку разбираться.
В ББ существуют так называемые методы только-для-реализации (implement-only).
Их можно вызывать только из того модуля, в котором они были определены (там где этот метод был объявлен впервые с пометкой NEW), а (пере)определять -- в потомках типа, уже где угодно (если метод допускает переопределение).
Совершенно необязательно, чтобы проверка SSN находилась в типе, содержащем указанный метод-для-реализации. Этим данный пример отличается от Вашего первого случая.
Проверка может происходить при вызове, а сам тип данных с информацией об этом знать не будет.
Какой-нибудь конкретный пример кода Вам лучше привел бы Илья Ермаков, прочитавший большое число модулей ББ, т.к. идея, кажется, вполне ясна, а сам я (в силу специфики своей деятельности ) почти всегда склоняюсь к более низкоуровневым средствам, нежели используемые в ББ.
В принципе, должно быть примерно так. Тип, содержащий данные о SSN, имеет метод GetSSN-, помеченный как implement-only (т.е. дефисом вместо звездочки).
Вызывать же его можно из какой-нибудь функции в модуле, где GetSSN объявлен впервые.
В этой функции, в зависимости от настройки системы, можно проверять и права доступа, и еще что-нибудь.
№ 3558 26-03-2007 16:58 | |
Ответ на »сообщение 3552« (Jack Of Shadows)
___________________________
Одно из возможных решений - просто разбить единый класс "данные" на три отдельных, применив парадигму Носитель-Курьер-Проектор (Carrier-Rider-Mapper), которая часто прмиеняется в ББ.
Данные сами по себе. Работать с ними можно только через курьер, который знает, как с ними работать. На верхнем уровне курьер оборачивается в требуемый проектор.
Хотя в некотором смысле аспекты могут быть удобны. Только для этого совершенно не нужно расширять язык, достаточно использовать метапрограммирование...
Концепцию, перекликающуюся с аспектами, но немного иной направленности, я делал в Active BlackBox - механизм автоагрегации деталей (см. http://oberoncore.ru/index.php?option=com_content&task=blogcategory&id=14&Itemid=10).
№ 3557 26-03-2007 16:27 | |
Ответ на »сообщение 3556« (AVC)
___________________________
пример в студию.
Какая буква из этой фразы вам не понятна ?
ПРИМЕР в студию!
Что вы предлагаете ? Пометить поле SSN как implement only ? И ? Чего вы этим добьетесь ?
Того что программист создаст метод класса, в котором будет проверять доступ пользователя к данным ?
Чем это отличается от способа номер 1, который я уже приводил, то есть забить код проверки доступа прямо в класс, хранящий данные ?
Не мытьем так катаньем ? :))
Добавить свое сообщение
Отслеживать это обсуждение
Дополнительная навигация: |
|