- •Программирование и алгоритмические языки. Курс за третий семестр. Введение в объектно-ориентированное программирование (ооп)
- •Именование типов в Object Pascal Тип данных «класс»
- •Инкапсуляция
- •Представление данных Данные как функции доступа Свойства
- •Иерархия типов Наследование реализации Проблемы наследования
- •Полиморфизм
- •Проблема множественности иерархий Агрегирование
- •Абстрактные методы и именованные интерфейсы
- •Описание сложного поведения
- •Эволюция пользовательского интерфейса
- •Автоматные модели описания поведения Сложное поведение как изменчивое поведение
- •Программы как символьные преобразования Алфавит как тип данных
- •Программы как синхронные преобразования
- •Тривиальное поведение
- •Нетривиальное поведение
- •Интеллект как рефлексивное, самоопределяемое поведение Машины Тьюринга
- •События как предикаты
- •Событийно управляемое исполнение программ в ооп Программы как тип данных
- •События конечного пользователя и системные, внешние и внутренние
- •Обработка исключений Делегирование
- •Живые данные
- •Задача (проблема) многих тел
- •События как исключения Исключения как события Обработка исключений в Delphi
События как предикаты
Автоматы работают с сообщениями (message), а не с событиями, с синтаксисом, а не семантикой. Разные сообщения могут относиться к одному событию. Следуя классической традиции, можно собрать сообщения в классы эквивалентности по отношению «иметь одно значение». Тогда сообщение определяет произвольный предикат принадлежности к классу, а проще – произвольный предикат. Интуитивно, событие – это случай, факт изменения, который всегда можно трактовать как изменение состояния.
Событие: гром грянул. Гром:=false; Гром:=true.
Содержательно, это именно фактическое изменение состояний, не любой предикат, а триггер. Формально: что можно описать как функцию на трассе значений переменной.
Если воспринимать событие как предикат, событийная схема при подходящем определении понятия внешнего состояния (состояния генератора событий) и внутреннего, локального состояния (состояния обработчика событий) превращается в подозрительно знакомую схему.
procedure Unstructured;
var state: tInnerState;
stop:boolean;
begin
state:=InitialState;
stop:=false;
while not stop do
begin
read(OuterState);
case
B1(state): state:=S1(state);
**********
Bn(state): state:=Sn(state);
{state – полное состояние декартового произведения внешнего и внутреннего
состояний }
end;
end;
write(OuterState, shift);
end;
Read – определение значений глобальных переменных, копирование глобальных в локальные; Write – из локальных в глобальные.
Это семантика обращения к процедуре.
Ту же схему (case) можно переписать иначе:
[if B(i,state) then] state:=Si(state);
Привели к форме разбора одного случая, возможно, неявного. Если трактовать предикат B как область определения процедуры S. Это структурная схема, либо
if B(1,state) then state:=S1(state) else {то же самое для i>1}
Это мы называли рекурсивным программированием (рекурсивная схема). Эти три формы связывают три базовых математических понятия: 1) понятие последовательности (в структурном программировании); 2) понятие дерева (рекурсивное программирование); 3) понятие отношения (автоматный подход: произвольные графы, событийные схемы).
Пример применения событийной схемы в процедурном программировании. Дан текстовый файл. Сосчитать максимальную длину слова.
Событийный стиль в данном контексте – управление входными данными. Написать программу по символьной обработке входного потока с разбором относящихся к делу случаев. Здесь – пробел – не пробел.
Событийно управляемое исполнение программ в ооп Программы как тип данных
Отвлекаясь от локальных состояний в ООП полей и свойств объекта, перепишем событийную схему. Все событийные схемы различаются только тем, какие сообщения поступают на вход и какие процедуры соответствуют каким событиям. В ООП сам цикл обработки событий спрятан от программиста, и (в наиболее простом случае, как в Delphi) набор событий ограничен и фиксирован. Программисту остаётся определить процедуры их обработки и подставить их в соответствие событиям. При этом необходимо учитывать, что процедуры должны быть написаны настолько Fool-Proof (дурозащитными), чтобы выдержать поступление сообщений в произвольном порядке. Знание этого порядка неявно предполагается программистом, но на деле ему неизвестен.
В более точных терминах ООП программист реализует интерфейс пользователя как набор процедур обработки сообщений. Пользователь сам определяет порядок их исполнения через последовательность сообщений.
Пример. Калькулятор. Программист реализует язык арифметических операций, пользователь задаёт арифметические выражения, определяющие последовательность действий.
Отметим, как в классическом программировании интерфейс явно отделён от реализации. Так в предыдущем примере можно неявно от пользователя подменить реализацию процедур или расширить функции (продолжение темы: смотри COM-технологии). Дополнительная нетривиальность в этом случае: пользователь не знает не только реализацию, но и действительные имена процедур (внутренний интерфейс). Так что суть обработки событий сводится к определению функции P, связывающей внешний и внутренний интерфейсы.