The problem of the Smart Ant-3
The problem of the Smart Ant-3

3.1. Проектирование

Первый вопрос, который следует обсудить: для чего понадобилось рассматривать объектно-ориентированный вариант автоматного программирования, какие проблемы традиционного программирования с явным выделением состояний способна решить объектная технология? Первая проблема — недостаточный уровень модульности. В системе, построенной с помощью метода, который описан в предыдущей главе, вычислительные состояния всех объектов управления и управляющие состояния всех автоматов глобальны — любой автомат или подпрограмма в системе имеет доступ к любым ее данным.

design

Такие избыточные зависимости делают систему неспособной к эволюции. Вторая проблема может быть незаметна в процессе изучения автоматного программирования и чтения этой книги, где все примеры сущностей и систем со сложным поведением довольно просты и проектируются «с чистого листа». Однако эта проблема становится существенной при переходе к промышленному программированию. На практике чаще всего возникает необходимость интегрировать реализацию сущностей со сложным поведением в уже существующие системы, а ведь огромная часть существующих промышленных программных систем написана в объектно-ориентированном стиле. Теперь подойдем к вопросу с другой стороны: если объектная технология так хороша, как о ней пишут, то есть ли необходимость внедрять в нее автоматный подход? Дело в том, что вопросы проектирования, спецификации и реализации сложного поведения лежат за рамками того круга проблем, которые обсуждаются и решаются в объектно-ориентированном программировании. Однако на эти вопросы нельзя закрывать глаза. Как было упомянуто выше, сущности со сложным поведением встречаются в программировании повсеместно. В последнее время часто приходится слышать от гуру индустрии разработки ПО, что в связи со все возрастающей сложностью программ необходимо использовать для их описания автоматы [59], однако широкое распространение автоматов в программировании сдерживается их конфликтом с господствующей объектно-ориентированной парадигмой. В чем же заключается этот конфликт? В объектной технологии сущности моделируются при помощи классов. Входное воздействие для класса — это вызов

design-0

design-1

design-2

компонента. Если ненадолго оставить в стороне полиморфизм, можно утверждать, что класс всегда реагирует на определенное входное воздействие выполнением одного и того же алгоритма действий, закодированного в теле соответствующего компонента. А это, как читатель, наверное, помнит, определение простого поведения. Таким образом, приходим к следующему выводу. класс является моделью сущности с простым поведением Это и есть глубинная причина непригодности объектной технологии в ее первоначальном виде для моделирования сущностей со сложным поведением. Логично предположить, что моделирование сложного поведения станет более простым и непосредственным, если добавить в объектную технологию элементы автоматного программирования. Однако как именно следует объединить две парадигмы — нетривиальный вопрос, и общепризнанного ответа на него пока не существует. Почти все обсуждения автоматных образцов проектирования строятся вокруг вопроса «Как с помощью объектов реализовать автоматы?» Такую поверхностную постановку задачи можно объяснить тем, что авторы образцов не знакомы с парадигмой автоматного программирования и не знают, что автоматные модели следует применять при разработке ПО систематически, для описания сложного поведения, а не от случая к случаю, как, например, при программировании компиляторов и решении еще нескольких специфических задач. Однако и в объектно-ориентированном программировании с явным выделением состояний на первых этапах его развития акценты были расставлены точно таким же образом. В первых работах (например, в работе [58]) по этой парадигме предполагалось, что процесс проектирования должен происходить так же, как при процедурном программировании с явным выделением состояний. Результатом этого процесса, как и раньше, должно было быть множество взаимодействующих автоматов и подпрограмм. И только после этого, уже на стадии реализации, в разработку вовлекался объектно-ориентированный подход: предпринимались попытки «втиснуть» эту совершенно чуждую объектной технологии древовидную архитектуру, основанную на функциях, в множество классов. При этом архитектура системы получается неприспособленной к модификации, непонятной, да и просто некрасивой — но это полбеды. Настоящая же беда начинается тогда, когда в стройную объектно-ориентированную систему, которая разрабатывалась долго и тщательно и имеет структуру на основе объектной декомпозиции, вдруг понадобится ввести сущность со сложным поведением. Для объектно-ориентированных систем введение новой сущности — это обыденная и безболезненная операция. Она требует добавления нового класса и небольших изменений в тех классах, которые должны стать его клиентами. Однако при описанном подходе к сочетанию автоматной и объектно-ориентированной парадигм вместо добавления одного класса придется перепроектировать всю систему с нуля в автоматном стиле. Не самая радужная перспектива! Таким образом, в настоящее время в индустрии разработки программного обеспечения сложилась ситуация, когда автоматы используются для описания поведения только в крайне сложных и ответственных системах, которые проще перепроектировать с нуля с применением автоматов, чем заставить правильно работать без них. В то же время за использование автоматов при разработке некритичного ПО приходится платить слишком высокую цену. Корни этой проблемы в том, что автомат продолжает восприниматься как подпрограмма. Даже если эта подпрограмма «обернута» в класс и переменная с номером текущего состояния инкапсулирована в этом классе (что само по себе неплохо) [58], сути дела такая «обертка» не меняет. В истории объектной технологии уже была похожая попытка построить объектно-ориентированный вариант некоторой концепции, просто обернув подпрограмму в класс. Речь идет о так называемых активных объектах — одной из моделей параллельных вычислений, которая основывается на отождествлении объекта и процесса (или потока). У класса, порождающего активные объекты, есть главная подпрограмма, выполнение которой отождествляется с работой процесса (потока).Модель активного объекта применяется в некоторых, в том числе популярных языках программирования, однако ее использование связано с рядом проблем (например, известная проблема аномалии наследования). Причина состоит в том, что эта модель не соответствует объектно-ориентированным концепциям. Класс должен описывать сущность, предоставляющую набор сервисов, а не программу. Таким образом, модель «автомат как подпрограмма» оказалась несостоятельной в рамках объектно-ориентированного подхода. Исторически следующей в объектно-ориентированном программировании с явным выделением состояний появилась концепция «автоматы и объекты управления как классы». Такая модель принята, например, в инструментальном средстве автоматного программирования UniMod (см. раздел 3.3.2). Архитектура системы со сложным поведением, построенная по такому принципу, изображена на рис. 3.1.Объекты управления довольно естественно превращаются в классы, у них все для этого есть: запросы, команды и вычислительное состояние, которое можно описать с помощью множества атрибутов класса. Сопоставление отдельного класса каждому объекту управления восстанавливает справедливость: теперь усилия разработчиков по выделению объектов управления на стадии моделирования не пропадают даром на этапе реализации. Каждый запрос или команда теперь имеют доступ только к строго определенной части вычислительного состояния. Гораздо интереснее вопрос, как сделать классы из автоматов. Вспомним, что существует несколько различных автоматных моделей. Например, активные автоматы довольно плохо согласуются с концепцией класса и являются, скорее, подпрограммами (или даже активными объектами, о которых было упомянуто выше). Лучше всего подходят на роль классов пассивные автоматы Мили. Сервисы, которые они предоставляют, — это события, которые они обрабатывают. Тела компонентов представляют собой реализацию функций переходов и выходов. При этом классы автоматов являются клиентами классов, реализующих объекты управления, и вызывают запросы и команды последних из своих компонентов. Клиентское отношение на рис. 3.1 изображено в соответствии с нотацией BON — стрелками, направленными от клиента к поставщику. Изложенный метод проектирования систем со сложным поведением, конечно, является более объектно-ориентированным, однако и он обладает рядом недостатков. Во-первых, он поддерживает автоматную декомпозицию и отношение вложенности между автоматами. Это отношение обладает специфической семантикой и не имеет аналогов среди межмодульных отношений в объектно-ориентированном мире. Введение такого отношения в структуру системы неоправданно усложняет ее. Во-вторых, в соответствии с концепциями объектной технологии классы должны описывать самостоятельные, четко определенные абстракции, которые имеют смысл и вне того контекста, где они были первоначально определены. Но является ли автомат самостоятельной абстракцией? Может ли автомат управления клапаном в другой системе начать управлять кофеваркой? При внимательном изучении становится ясно, что самостоятельной абстракцией в автоматной архитектуре является не отдельно взятый автомат, а вся сущность со сложным поведением в целом. Для того чтобы реализация сущности со сложным поведением органично вписывалась в объектно-ориентированную систему, модель такой сущности должна быть согласована с объектно-ориентированными концепциями, а следовательно, как и модель любой другой сущности, она должна быть классом. моделью сущности со сложным поведением должна быть специальная разновидность класса Так же, как и обыкновенный класс, эта модель должна предоставлять клиентам набор сервисов, соответствующих событиям, которые обрабатывает автомат. Однако в подводной части айсберга, скрытой от клиентов (в своей реализации), модель сущности со сложным поведением должна отличаться от обыкновенного класса. При вызове компонента выбор выполняемого действия (тела компонента) должен осуществляться в зависимости от управляющего состояния. В разделе 1.4.3 была построена математическая модель автоматизированного объекта управления. Для сущности со сложным поведением эта модель — практически то же, что и абстрактный тип данных для сущности с простым поведением. Различие состоит лишь в том, что в автоматизированном объекте отсутствует в явном виде описание семантики операций объекта управления. Возможно, этот недочет в будущем будет исправлен. Пожалуй, пора раскрыть карты и признаться читателю, что модель автоматизированного объекта управления строилась [61, 62] как частный случай абстрактного типа данных. Это всего лишь АТД со специфическим внутренним устройством (АТД, содержащий автомат).Поскольку реализацией абстрактного типа данных в объектной технологии является класс, то автоматизированный объект управления естественно реализовать с помощью класса. Так мы приходим к следующей (и последней на сегодняшний день) концепции объектно-ориентированного программирования с явным выделением состояний, которую можно назвать «автоматизированные объекты управления как классы» (рис. 3.2).Здесь может возникнуть путаница с терминами: объектами в объектно-ориентированном программировании называются экземпляры класса. В то же время автоматизированный объект управления (как и просто объект управления) — это скорее класс, чем объект. Эта путаница возникла в результате конфликта терминов в объектной технологии и теории управления. В данной главе, когда будем говорить о программном, а не о математическом описании, будем употреблять для модели сущности со сложным поведением термин автоматизированный класс. Эта концепция полностью согласуется и с объектно-ориентированными принципами, и с парадигмой автоматного программирования. Автоматы здесь используются только для описания логики сущностей со сложным поведением, а сущности с простым поведением, присутствующие в той же системе, описываются обыкновенными классами. До сих пор речь шла лишь о том, что автоматизированный класс должен выглядеть как обыкновенный класс с точки зрения клиентов1, но о внутреннем устройстве этого класса пока ничего не известно. В частности, не утверждается, что объекту управления не следует сопоставить отдельный класс. Напротив, объект управления часто представляет собой самостоятельную абстракцию. В этом случае можно предложить следующий образец проектирования автоматизированных объектов управления (рис. 3.3).Здесь и объект управления, и автоматизированный объект управления представлены классами, между которыми существует клиентское отношение. При этом классы-клиенты сущности со сложным поведением обращаются к автоматизированному классу (как к обыкновенному). Если же на более низком уровне абстракции в системе есть сущности, которые нуждаются в сервисах объекта управления, они обращаются напрямую к нему.*1 Для модулей объектно-ориентированной системы так же естественно общаться с другими классами посредством вызова компонентов, как для вас — общаться с другими людьми с помощью речи, мимики и жестов. Пытаясь заставить класс взаимодействовать не с другим классом, а с автоматом, представьте, каково было бы вам общаться с пришельцем с
другой планеты, зная лишь понаслышке о логике его мышления и способах коммуникации. Этот образец проектирования не является единственно возможным. В том случае, если объект управления не представляет собой достаточно самостоятельной абстракции так, что его нецелесообразно выделять в отдельный класс, реализацию запросов и команд объекта управления можно поместить непосредственно в автоматизированный класс. Более того, часть или все операции объекта управления могут быть реализованы в других классах системы. Другими словами, у автоматизированного класса может быть не один непосредственный поставщик (как на рис. 3.3), а несколько (рис. 3.4). В этом случае объект управления не представлен непосредственно модулем программной системы, он существует на более высоком уровне абстракции. При необходимости отдельный класс для объекта управления легко ввести: это будет всего лишь адаптер, транслирующий вызовы компонентов в автоматизированном классе его поставщикам. У тех разработчиков, которые мыслят категориями программирования с явным выделением состояний, может возникнуть вопрос: всегда ли возможно обойтись без автоматной декомпозиции? Что если в результате выделения сущностей со сложным поведением автомат, управляющий некоторым объектом управления, получился слишком сложным? В рамках подхода «автоматизированные объекты управления как классы» предлагается всегда использовать только один вид декомпозиции, который уже существует в объектной технологии, — объектную декомпозицию. Это означает, что если автоматизированный класс слишком сложен, его необходимо разбить на несколько классов, обыкновенных или автоматизированных. В связи с этим обычно возникают возражения двух типов. К первому типу относятся замечания, что объект управления может быть спроектирован заранее (разработан другой компанией, реализован аппаратно) и в этом случае нет возможности провести его декомпозицию. Возразим, что в этом случае объект управления неделим на уровне реализации, однако при построении архитектуры системы со сложным поведением ничто не мешает разработчикам представить его как составной. Например, пусть заранее разработан низкоуровневый эмулятор микроволновой печи, представляющий собой один класс, который, в том числе, имеет компоненты «Открыть замок дверцы» и «Запустить таймер». Это не мешает при разработке системы управления печью считать, что в составе печи есть замок дверцы и таймер, и разработать по автомату для управления каждым из этих объектов в отдельности. На этапе реализации необходимо учесть, что обе эти абстракции были совмещены в одном классе (например, можно ввести в систему классы-адаптеры или просто сопоставить сервисам замка и таймера различные компоненты класса микроволновой печи). Эта проблема — следствие выбора не совсем подходящих компонентов для повторного использования. Она не специфична для сложного поведения и применения автоматов. Такое часто бывает в объектно-ориентированном программировании, если повторно используемые компоненты были спроектированы неидеально.
Ко второму типу относятся замечания о том, что если логика поведения сущности сложна, причем во всех управляющих состояниях происходит обращение ко всем компонентам объекта управления, то разбить автоматизированный объект на несколько независимых автоматизированных объектов невозможно. Такая ситуация возникает редко, но и эту проблему можно решить, не прибегая к изменению модели сущности со сложным поведением и не нарушая стройности объектной технологии. В разделе 1.4.3 упоминалось, что автоматное программирование поддерживает концепцию выделения уровней абстракции, позволяя объекту управления самому быть автоматизированным. В процедурном программировании с явным выделением состояний эта конструкция косвенно могла быть реализована с помощью иерархической автоматной декомпозиции: вложенные и вызываемые автоматы как бы являлись объектами управления для автомата более высокого уровня. Такой способ выделения уровней абстракции лишен единообразия: автоматы и объекты управления — это все-таки разные сущности и взаимодействовать с ними приходится по-разному, что ведет к усложнению модели. При объектно ориентированном подходе концепция вложенных автоматизированных объектов управления реализуется непосредственно. Интерфейс автоматизированного класса ничем не отличается от любого другого. Поэтому ничто не мешает классу объекта управления быть автоматизированным. Таким образом, здесь для выделения уровней абстракции используется стандартное клиентское отношение между классами, модель не усложняется дополнительными сущностями и отношениями (вложенными и вызываемыми автоматами), а результирующая архитектура получается более модульной (готовый автоматизированный класс можно использовать в качестве объекта управления в любом другом автоматизированном классе).В завершение обсуждения опишем процесс проектирования системы со сложным поведением в соответствии с концепцией «автоматизированные объекты как классы» в виде алгоритма (по аналогии с главой 2, где подобный алгоритм был приведен для процедурного программирования с явным выделением состояний).Производи тся объектная декомпозиция: программная система представляется 1. в виде множества взаимодействующих сущностей, каждая из которых является самостоятельной, четко определенной абстракцией. Каждой сущности сопоставляется класс, определяются интерфейсы классов 2. и отношения между ними. Из числа сущностей выделяются те, которые обладают сложным поведением: 3. для описания именно этих сущностей будет применяться автоматный подход.Для каждой сущности со сложным поведением в отдельности:4.строится набор управляющих состояний;•компоненты, заданные в интерфейсе, сопоставляются событиям управляющего автомата; запросы и команды объекта управления сопоставляются соответственно входным и выходным переменным управляющего автомата; на основе управляющих состояний, событий, входных и выходных переменных строится управляющий автомат. Обыкновенные, неавтоматизированные классы системы реализуются непосредственно на выбранном объектно-ориентированном языке программирования. Код автоматизированных классов может либо генерироваться автоматически на основе диаграмм переходов, либо строиться вручную с помощью одного из известных образов проектирования (см. параграф 3.3).Обратим внимание читателя на то, что в приведенном выше алгоритме существенными являются лишь аспекты проектирования и реализации сложного поведения. Предложенный метод не ограничивает программиста в выборе модели процесса разработки (водопадная, итеративная, кластерная и т. п.). Приведенный выше алгоритм легко модифицировать таким образом, чтобы разработка системы происходила в несколько итераций, а также чтобы это была не разработка «с нуля», а внесение изменений в уже существующую объектно-ориентированную систему.

3.2. Спецификация

1.7.2.Объем и тип оперативной памяти видеокарты

Программирование логических контроллеров ПЛК-автоматов