Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Shalyto_Polikarpova_Avtomatnoe_Programmirovanie

.pdf
Скачиваний:
31
Добавлен:
29.03.2016
Размер:
1.76 Mб
Скачать

Рис. 3.15. Диаграмма классов образца проектирования State

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

Рис. 3.16. Диаграмма классов образца проектирования State на примере часов с будильником

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

Листинг 3.3. Реализация часов с будильником на основе образца проектирования

State

// Реализация автоматизированного класса class Alarm_Clock {

public:

Alarm_Clock(Clock_Control_Object* control_object) :

state(new Alarm_Off(control_object))

{}

void h_button() {

 

121

state->h_button(); update_state();

}

void m_button() { state->m_button(); update_state();

}

void a_button() { state->a_button(); update_state();

}

void tick() { state->tick(); update_state();

}

private:

State* state;

void update_state() {

State* next_state = state->next_state(); delete state;

state = next_state;

}

}

//Абстрактный класс состояния class State {

public:

virtual void h_button() = 0; virtual void m_button() = 0; virtual void a_button() = 0; virtual void tick() = 0; State* next_state;

private: Clock_Control_Object* co;

}

//Конкретное состояние «Будильник выключен» class Alarm_Off : public State {

public:

Alarm_Off(Clock_Control_Object* control_object) : co(control_object) {}

virtual void h_button() { co->increase_hours();

122

next_state = new Alarm_Off(co);

}

virtual void m_button() { co->increase_minutes(); next_state = new Alarm_Off(co);

}

virtual void a_button() {

next_state = new Alarm_Setting(co);

}

virtual void tick() { co->increase_time(); next_state = new Alarm_Off(co);

}

}

//Конкретное состояние «Установка времени будильника» class Alarm_Setting : public State {

... // Аналогично Alarm_Off

}

//Конкретное состояние «Будильник включен»

class Alarm_On : public State {

... // Аналогично Alarm_Off

}

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

Итак, вновь рассмотрим последовательный двоичный одноразрядный сумматор. Граф переходов автомата Мили, реализующего сумматор, приведен на рис. 1.18. В соответствии с объектно-ориентированным подходом, выделим в отдельный класс Position объект управления сумматора. Объектом управления в этой задаче можно считать совокупность текущих двоичных разрядов первого и второго слагаемого, а также результата.

Вэтой системе изначально нет событий, а управляющий автомат является активным.

Всвязи с необходимостью перехода к пассивной автоматной модели искусственно

введем единственное событие next_position, которое будет сигнализировать о том, что очередные разряды первого и второго слагаемых готовы, и можно вычислять очередной разряд суммы. Диаграмма классов реализации сумматора с

123

помощью образца проектирования State приведена на рис. 3.17, а программный текст – в листинге 3.4.

Рис. 3.17. Диаграмма классов образца проектирования State на примере последовательного двоичного одноразрядного сумматора

Листинг 3.4. Реализация последовательного двоичного одноразрядного сумматора на основе образца проектирования State

//Реализация объекта управления struct Position {

bool x; // Текущий разряд первого слагаемого bool y; // Текущий разряд второго слагаемого bool z; // Текущий разряд суммы

}

//Реализация автоматизированного класса

class Adder { public:

Adder(Position* co) : state (new Carry_0(co)) {};

void next_position() { state->next_position(); update_state();

}

private:

State* state;

void update_state() {

State* next_state = state->next_state(); delete state;

state = next_state;

}

}

// Абстрактный класс состояния class State {

public:

virtual void next_position() = 0;

124

State* next_state; private:

Position* co;

}

// Конкретное состояние «В переносе 0» class Carry_0 : public State {

public:

Carry_0 (Position* control_object) : co(control_object) {}

virtual void next_position() { if (!co->x && !co->y) {

co->z = 0;

next_state = new Carry_0(co);

}else if (co->x && co->y) { co->z = 0;

next_state = new Carry_1(co);

}else {

co->z = 1;

next_state = new Carry_0(co);

}

}

}

// Конкретное состояние «В переносе 1» class Carry_1 : public State {

public:

Carry_1 (Position* control_object) : co(control_object) {}

virtual void next_position() { if (!co->x && !co->y) {

co->z = 1;

next_state = new Carry_0(co);

}else if (co->x && co->y) { co->z = 1;

next_state = new Carry_1(co);

}else {

co->z = 0;

next_state = new Carry_1(co);

}

}

}

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

125

тактового генератора. Поскольку образец проектирования State предназначен для реализации автоматов Мили, необходимо модифицировать автомат Мура счетного триггера, переместив действия из каждого состояния на все переходы, которые ведут в это состояние. Диаграмма классов реализации счетного триггера на основе образца проектирования State приведена на рис. 3.18, а программный текст – в листинге 3.5.

Button

+ pressed: boolean

Lamp

+on

+off

Trigger

 

State

 

+ tick

state

+ tick

next_state

 

 

 

- update_state

 

 

 

Released_Off

 

Pressed_On

 

Released_On

 

Pressed_Off

 

 

 

 

 

 

 

+ tick

 

+ tick

 

+ tick

 

+ tick

 

 

 

 

 

 

 

Рис. 3.18. Диаграмма классов образца проектирования State на примере счетного триггера

Листинг 3.5. Реализация счетного триггера на основе образца проектирования State

// Реализация объекта управления struct Button {

bool pressed; // Нажата ли кнопка?

}

struct Lamp {

void on(); // Подавать питание на лампу void off(); // Не подавать питание на лампу

}

// Реализация автоматизированного класса class Trigger {

public:

Trigger(Button* b, Lamp* l) : state (new Released_Off(b, l)) {};

void tick() { state->tick(); update_state();

}

private:

State* state;

126

void update_state() {

State* next_state = state->next_state(); delete state;

state = next_state;

}

}

//Абстрактный класс состояния class State {

public:

virtual void tick() = 0; State* next_state;

private: Button* b; Lamp* l;

}

//Конкретное состояние «Кнопка отпущена, лампа выключена» class Released_Off : public State {

public:

Released_Off (Button* button, Lamp* lamp) : b(button), l(lamp) {}

virtual void tick() { if (b->pressed) {

l->on();

next_state = new Pressed_On(b, l); } else {

l-off();

next_state = new Released_Off(b, l);

}

}

}

// Конкретное состояние «Кнопка нажата, лампа включена» class Pressed_On : public State {

public:

Pressed_On (Button* button, Lamp* lamp) : b(button), l(lamp) {}

virtual void tick() { if (b->pressed) {

l->on();

next_state = new Pressed_On(b, l); } else {

l->on();

next_state = new Released_On(b, l);

}

}

127

}

// Конкретное состояние «Кнопка отпущена, лампа включена» class Released_On : public State {

... // Аналогично

}

// Конкретное состояние «Кнопка нажата, лампа выключена» class Pressed_Off : public State {

... // Аналогично

}

3.3.2. Инструментальное средство UniMod

Переходя к обсуждению инструментального средства для поддержки объектноориентированного программирования с явным выделением состояний, отметим, что если для генерации программ по автоматам кроме средств, рассмотренных в разд. 2.3.3, известны также и многие другие, то рассматриваемое здесь решение задачи об автоматизации построения объектно-ориентированных программных систем со сложным поведением в целом единственное в своем роде. Это объясняется тем, что по сравнению с другими средствами визуального конструирования объектно-ориентированных программ (IBM Rational Rose, Borland Together, Telelogic Rhapsody) их проектирование в инструментальном средстве UniMod осуществляется так же, как выполняется автоматизация объектов управления в промышленности. Кроме того, по сравнению с аналогами оно является открытым и бесплатным [70].

Авторы проекта UniMod [69, 71] предложили, во-первых, метод и язык моделирования для описания систем со сложным поведением (язык является подмножеством UML), а во-вторых, реализовали инструментальное средство, которое позволяет описывать системы на этом языке, проверять их корректность, интерпретировать или компилировать их, и даже отлаживать.

Процесс разработки системы со сложным поведением с помощью этого инструментального средства состоит в следующем.

1.На основе анализа предметной области производится объектная декомпозиция системы, определяются сущности и отношения между ними.

2.В отличие от традиционных для объектно-ориентированного программирования подходов, из числа сущностей выделяются источники событий, объекты управления и автоматы. Источники событий активны – они по собственной инициативе воздействуют на автомат. Объекты управления пассивны и выполняют действия по команде от автомата. Они также формируют значения входных переменных для автомата. Автомат активируется источниками событий и на основании значений входных переменных и текущего состояния воздействует на объекты управления и переходит в новое состояние.

3.С использованием нотации диаграммы классов, строится схема связей автомата, которая задает его интерфейс. На этой схеме слева отображаются источники событий, в центре – автоматы, а справа – объекты управления. Источники событий с помощью UML-ассоциаций связываются с автоматами, которым они

128

поставляют события. Автоматы связываются с объектами, которыми они управляют.

4.Каждый объект управления содержит два типа компонентов, реализующих входные (xj) и выходные переменные (zk).

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

6.Состояния на графе переходов могут быть простыми и составными (суперсостояния). Если в состояние вложено другое состояние, то оно является составным. В противном случае состояние простое. Основной особенностью составных состояний является то, что дуга, исходящая из такого состояния, заменяет однотипные дуги из каждого вложенного состояния.

7.Компоненты объекта управления, соответствующие входным и выходным переменным, реализуются вручную на целевом языке программирования.

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

На рис. 3.19 приведена схема связей автомата, а на рис. 3.20 – его граф переходов, построенные с помощью инструмента UniMod.

129

Рис. 3.19. Пример схемы связей автомата

Рис. 3.20. Пример графа переходов автомата

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

130