OberonCore https://forum.oberoncore.ru/ |
|
Моделирование интерфейсов https://forum.oberoncore.ru/viewtopic.php?f=29&t=3640 |
Страница 4 из 6 |
Автор: | Сергей Губанов [ Воскресенье, 18 Декабрь, 2011 20:38 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
Архитектурно там просто: структура данных и набор процедур. |
Автор: | jackbauer [ Воскресенье, 18 Декабрь, 2011 21:22 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
Александр Ильин писал(а): Когда вы говорите "не эквивалентна", вы имеете в виду только синтаксические отличия (количество параметров в процедуре) или существо дела? Приведите возражения по существу. В данном случае разное количество параметров - существенное различие. В одном случае передается явный указатель на виртуальную таблицу, в другом не передается. Важность этого различия можно понять только попробовав реализовать на Обероне вариант с одним параметром, как в примере на C#. |
Автор: | Valery Solovey [ Воскресенье, 18 Декабрь, 2011 23:54 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
Ну вот, допустим, смотрю я на только что реализованный вариант с одним параметром. Как я должен ощутить "важность этого различия"? |
Автор: | jackbauer [ Понедельник, 19 Декабрь, 2011 01:24 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
Valery Solovey писал(а): Ну вот, допустим, смотрю я на только что реализованный вариант с одним параметром. Как я должен ощутить "важность этого различия"? Можно показать этот вариант? |
Автор: | Valery Solovey [ Понедельник, 19 Декабрь, 2011 12:20 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
jackbauer писал(а): Можно показать этот вариант? С этим потом. Сначала давайте разберёмся с первым вопросом: как увидеть важность/существенность различия?
|
Автор: | Александр Ильин [ Понедельник, 19 Декабрь, 2011 13:02 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
Valery Solovey писал(а): С этим потом. Сначала давайте разберёмся с первым вопросом: как увидеть важность/существенность различия? Ага! Вопрос о критерии. Хороший ход.
|
Автор: | Trurl [ Среда, 21 Декабрь, 2011 09:04 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
jackbauer писал(а): В одном случае передается явный указатель на виртуальную таблицу Почему на виртуальную? На вполне реальную таблицу. |
Автор: | Дмитрий Грачёв [ Суббота, 01 Сентябрь, 2012 23:36 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
Илья Ермаков писал(а): Как всегда, есть случаи, когда декомпозиция на части будет как раз лучшим дизайном (а попытка наследовать множественные интерфейсы - недопроектированием), и случаи, когда она уже будет "эмуляцией", а более естественным было бы второе. Илья, не могли бы Вы привести пару примеров, когда лучше первое, а когда второе, и почему? |
Автор: | Илья Ермаков [ Воскресенье, 02 Сентябрь, 2012 10:15 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
Давайте попробуем. Пусть у нас есть абстрактные интерфейсы чтения и записи двоичных данных. И разные классы, способные хранить двоичные данные (допустим, кольцевой буфер, файл, ещё какой-нибудь буфер, файл в памяти, BLOB, да что угодно). Ну, самая грубая ошибка проектирования была бы, конечно, реализовать интерфейсы чтения и записи прямо в классе-носителе данных. Ну такую ошибку вряд ли допустит кто-то, кроме студентов, но всё может быть... Следуя BlackBox-овому паттерну Carrier-Rider-Mappper (точнее, его первой части Carrier-Rider) мы сделаем объекты чтения и записи (riders - объекты доступа), реализующие соотв. интерфейсы, и позволим иметь много объектов доступа к одному носителю. Это несколько похоже на итераторы. Кроме возможности "быть в разных позициях" одновременно, это даёт возможность разделять полномочия кода - если алгоритм просит только Reader, то он не может получить доступ к носителю на модификацию (правда, в стандартных ББ-шных компонентах можно и через Reader добраться до его носителя, но я лично обычно изолирую). Далее. У объектов доступа есть возможность позиционирования (некая пара Pos(): INTEGER, SetPos (INTEGER)). Но не все объекты допускают позиционирование (например, буфер поступающих из сети данных с однократным чтением). Решение в рамках интерфейсов - вынести операции позиционирования в отдельный интерфейс Slider - и пусть объекты доступа одних носителей этот интерфейс реализуют, а других - нет. Но ещё лучше "допроектировать" и сделать этот Slider отдельным объектом, тогда можно, опять же явно декларировать и гарантировать, что некоторый алгоритм - "однопроходный", т.к. он не имеет доступа к Slider-у. Например, он имеет право дописывать с того места, на котором ему дали writer, а модифицировать что-то ещё в буфере - нет. Особенно актуальны такие вещи, если мы работаем через такие интерфейсы с ОЗУ и разными хранилищами, а не тупо с файлами или сетью... Нужно отметить, что идею с отделением объекта Slider некогда у нас тут высказал Сергей Губанов. Живой пример, как это выглядит (с "купюрами", правда): Код: DEFINITION SomemylibData; TYPE Carrier = POINTER TO ABSTRACT RECORD (c: Carrier) NewReader (): Reader, NEW, ABSTRACT; (c: Carrier) NewWriter (): Writer, NEW, ABSTRACT; (c: Carrier) Slider (): Slider, NEW, ABSTRACT END; Rider = POINTER TO ABSTRACT RECORD END; Reader = POINTER TO ABSTRACT RECORD (Rider) (r: Reader) Available (): LONGINT, NEW, ABSTRACT; (r: Reader) LookBytes (OUT x: ARRAY OF BYTE; beg, len: INTEGER), NEW, ABSTRACT; (r: Reader) ReadBytes (OUT x: ARRAY OF BYTE; beg, len: INTEGER), NEW, ABSTRACT; (r: Reader) Skip (len: INTEGER), NEW, ABSTRACT END; Writer = POINTER TO ABSTRACT RECORD (Rider) (w: Writer) WriteBytes (IN x: ARRAY OF BYTE; beg, len: INTEGER), NEW, ABSTRACT END; Slider = POINTER TO ABSTRACT RECORD (s: Slider) Length (rider: Rider): LONGINT, NEW, ABSTRACT; (s: Slider) PosOf (rider: Rider): LONGINT, NEW, ABSTRACT; (s: Slider) SetPos (rider: Rider; pos: LONGINT), NEW, ABSTRACT END; PROCEDURE CopyBytes (reader: Reader; writer: Writer); END SomemylibData. Теперь обратите внимание на важную "фишку". Если Reader и Writer - это объекты доступа, которые создаются (NewReader(), NewWriter()), потому что они должны хранить контекст взаимодействия с носителем - позицию, то любая реализация Slider - это синглтон. Реализация слайдера не имеет состояния, создана в единственном экземпляре, возвращается одна и та же процедурой Slider() для всех носителей некоторого вида. А уже объект доступа, который нужно отпозиционировать, передаётся ей через параметр. Т.е., например, для некоторого модуля, реализующего какие-нить буферы, будет: Код: MODULE... TYPE Slider = POINTER TO RECORD (Data.Slider) END; VAR slider: Slider; PROCEDURE (buf: Buffer) Slider (): Slider; BEGIN RETURN slider END Slider; BEGIN NEW(slider) END ... Получаем, что интерфейс реализован даже без накладных расходов, т.е. количество объектов в памяти не умножается... Доп. интерфейс к объекту реализуется через объект-синглтон, который несёт на себе только функции виртуализации вызова. |
Автор: | Илья Ермаков [ Воскресенье, 02 Сентябрь, 2012 10:29 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
Если раньше я высказал мнение, что в некоторых случаях это не выгодно, а всего лишь "эмуляция множественных интерфейсов", то последнее время, после того, как пришлось пореализовывать архитектуры такого типа, я склоняюсь к тому, что никакая это не "эмуляция", а просто более явный способ их реализовывать. Интерфейс, фактически, реализуется через отдельный объект - и это позволяет иметь POINTER TO ИНТЕРФЕЙС, т.е. разделять полномочия кода и проч. Что мы получаем при более высокоуровневом, типа, подходе, с интерфейсами и их множественным наследованием: то же самое внутри, спрятано от программиста, и наверняка кто-нибудь где-нибудь уже начал изобретать новый язык, где можно делать POINTER TO ИНТЕРФЕЙС и разделять полномочия... Сначала спрячем, а потом накручиваем сверху эмуляцию - прямо как функциональщики спрятали последовательность действий, а потом вводят монады и проч. Одно может оставаться неясным: как мы можем заставить любой попавший к нам в руки объект отдать любой интересующий нас интерфейс (или проверить, что он его имеет). В паре с паттерном HandleMsg и это возможно. Пусть наши объекты расширяют некоторый базовый тип, имеющий процедуру HadnleMsg (VAR rec: ANYREC). У нас есть модуль, в котором определён интерфейс: Код: DEFINITION M; TYPE Interface = POINTER TO ABSTRACT RECORD .... END; GetInterfaceMsg = RECORD ifc: Interface END; END M; К нам в руки попал объект obj. Мы хотим запросить у него интерфейс Interface. Делаем: VAR msg: M.GetInterfaceMsg; obj.HandleMsg(msg). |
Автор: | Дмитрий Грачёв [ Воскресенье, 02 Сентябрь, 2012 12:07 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
Илья Ермаков писал(а): Если раньше я высказал мнение, что в некоторых случаях это не выгодно, а всего лишь "эмуляция множественных интерфейсов", то последнее время, после того, как пришлось пореализовывать архитектуры такого типа, я склоняюсь к тому, что никакая это не "эмуляция", а просто более явный способ их реализовывать. То же самое прочитал и здесь kemiisto писал(а): Подробности озвученного подхода от, так сказать, отцов-основателей тут. J. Templ. A systematic approach to multiple inheritance implementation писал(а): Conclusions It has been shown that independent multiple inheritance can be expressed by multiple application of single inheritance. Support for multiple inheritance in a programming language does not increase the expressive power of the language, but simplifies the implementation of structures like twin objects. It also allows a more efficient implementation which is based on (but does not affect) the implementation of single inheritance. The efficiency differences between an emulation, the C++ implementation, and our approach are, however, almost not noticeable. Thus the advantage of multiple inheritance support in a programming language is purely syntactical. В конце автор приходит к тому, что множественное наследование - это способ скрыть от программиста ссылки между объектами, и доказывает, что практически никакого выигрыша в производительности это не дает. Выигрыш один - меньше надо писать. Но при этом оно не позволяет Илья Ермаков писал(а): иметь POINTER TO ИНТЕРФЕЙС, т.е. разделять полномочия кода и проч.
|
Автор: | Дмитрий Грачёв [ Воскресенье, 02 Сентябрь, 2012 12:12 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
Спасибо, многое прояснилось. |
Автор: | Дмитрий Грачёв [ Воскресенье, 02 Сентябрь, 2012 12:15 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
Илья Ермаков писал(а): и наверняка кто-нибудь где-нибудь уже начал изобретать новый язык, где можно делать POINTER TO ИНТЕРФЕЙС и разделять полномочия... Вы не поверите, но я что-то очень похожее набросал в блокноте перед Вашим постом |
Автор: | Илья Ермаков [ Воскресенье, 02 Сентябрь, 2012 12:25 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
Ну и хорошо, что всё так понятно Хорошо бы, Дмитрий, из наших с вами сообщений сделать статью в нашу вики.... Блин, у меня времени сейчас нет... Может быть, позже, или кто-нибудь ещё возьмётся... |
Автор: | Илья Ермаков [ Воскресенье, 02 Сентябрь, 2012 12:34 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
Ещё отметим такой момент. Вспомним обероновское ООП, где методы делались полями RECORD-а: Object = POINTER TO RECORD Method: PROCEDURE (obj: Object; ....) Т.е., фактически, виртуальная таблица делалась явной. Это более мощный подход, чем обычное ООП, но на практике обычные методы оказались очень широко применимыми и удобными. При наличии "обычных методов" мы можем при необходимости применять идею явной виртуализации, как бы, на новом уровне, имея уже не процедурные переменные, а переменные - ABSTRACT-интерфейсы. Идея явной передачи this-параметра этим интерфейсам сохраняется. |
Автор: | Дмитрий Грачёв [ Воскресенье, 02 Сентябрь, 2012 15:45 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
Илья Ермаков писал(а): Одно может оставаться неясным: как мы можем заставить любой попавший к нам в руки объект отдать любой интересующий нас интерфейс (или проверить, что он его имеет). В паре с паттерном HandleMsg и это возможно. Разработчики среди недостатков такого подхода отмечают (Design Patterns, 9.4.1 Message Object): Цитата: The message handler analyses the messages at runtime with a WITH-statement. The branches of this WITH statement are processed sequentially. This is generally slower than a method call, which is usually implemented by a direct access to a method table (see Appendix A.12.4). Насколько критично такое замедление? Внутренний голос говорит, что <1мс - это не проблема. Но хотелось бы услышать еще мнения. |
Автор: | Илья Ермаков [ Воскресенье, 02 Сентябрь, 2012 15:56 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
Операция IS в Обероне выполняется очень быстро, за одно сравнение (так организованы дескрипторы типов). Последовательный перебор в WITH, конечно, имеет место быть, но 2-3 ветки - то же самое, что IF. Там для 1мс нужно не одну сотню раз WITH-кнуть... |
Автор: | Илья Ермаков [ Воскресенье, 02 Сентябрь, 2012 15:58 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
Главное преимущество HandleMsg - можно увязывать компоненты, ничего не знающие друг о друге. Это такой контролируемый вид динамической типизации, "утиной", в строгом языке. |
Автор: | Илья Ермаков [ Воскресенье, 02 Сентябрь, 2012 16:04 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
Дмитрий Грачёв писал(а): Разработчики среди недостатков такого подхода отмечают (Design Patterns, 9.4.1 Message Object): Это из Project Oberon? |
Автор: | Дмитрий Грачёв [ Воскресенье, 02 Сентябрь, 2012 16:08 ] |
Заголовок сообщения: | Re: Моделирование интерфейсов |
Илья Ермаков писал(а): Дмитрий Грачёв писал(а): Разработчики среди недостатков такого подхода отмечают (Design Patterns, 9.4.1 Message Object): Это из Project Oberon? Цитата: Design Patterns in
Oberon-2 and Component Pascal translated excerpts from Objektorientierte Programmierung in Oberon-2 by Hanspeter Mössenböck English translation: Bernhard Treutwein, last c ha nge s : Authorized translation of Chapter 9 "Entwurfsmuster" of Hanspeter Mössenböck: Objektorientierte Programmierung in Oberon-2, 3rd Edition, 1998. Permission granted by Springer, Heidelberg. |
Страница 4 из 6 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |