Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Design Patterns via C#.pdf
Скачиваний:
154
Добавлен:
17.03.2016
Размер:
13.25 Mб
Скачать

256

Мотивация

В качестве примера использования паттерна State предлагается построить машину состояний описывающую поведение отца, отправившего сына в школу. Условимся, что сын может получать только двойки или пятерки. Отец не хочет браться за ремень каждый раз, когда сын получает двойку и выбирает более тонкую тактику воспитания. Граф автомата, моделирующего умное поведение отца представлен ниже.

Граф 3.

Этот автомат имеет:

четыре состояния в которых может пребывать отец, S = { s0, s1, s2, s3 }, где:

s0 – Neutral (Нейтральное состояние)

s1 – Pity (Жалость)

s2 – Anger (Гнев)

s3 – Joy (Радость)

два входных сигнала – оценки полученные сыном в школе X = { x0, x1 }, где:

x0 = 2

x1 = 5

шесть выходных сигналов, т.е., действий отца Y = { y0, y1, y2, y3, y4, y5 }, где:

y0 - брать ремень;

y1 - ругать сына;

y2 - успокаивать сына;

y3 - надеяться;

y4 - радоваться;

y5 - ликовать;

Сына, получившего одну и туже оценку – ожидает дома совершенно различная реакция отца в зависимости от предыстории его учебы. Отец помнит, как его сын учился раньше и строит модель воспитания с учетом успехов и неудач сына. Например, после третьей двойки в истории (2, 2, 2) сына встретят ремнем (y0), а в истории (2, 2, 5, 2) – будут успокаивать(y2).

Каждая предыстория определяет текущее состояние автомата, при этом некоторые входные предыстории эквивалентны (те истории которые приводят автомат в одно и тоже состояние), например, история (2, 2, 5) эквивалентна пустой истории, которой соответствует начальное состояние.

257

Представим данный автомат таблично. Таблица 4 - определяет функцию переходов автомата из одного состояния в другое.

Функция переходов δ (sn, xn) определяется так: δ (s0, 2) = s1; δ (s2, 5) = s0; ….

δ

2

5

 

 

 

s0 - Neutral

s1

s3

 

 

 

s1 - Pity

s2

s0

 

 

 

s2 - Anger

s2

s0

 

 

 

s3 - Joy

s1

s3

 

 

 

Таблица 4.

Таблица 5 - определяет функцию выходов λ (sn, xn) так: λ (s0, 2) = y2; λ (s2, 5) = y3; ….

λ

2

5

 

 

 

s0 - Neutral

y2 - успокаивать сына

y4 - радоваться

 

 

 

s1 - Pity

y1 - ругать сына

y3 - надеяться

 

 

 

s2 - Anger

y0 - брать ремень

y3 - надеяться

 

 

 

s3 - Joy

y2 - успокаивать сына

y5 - ликовать

 

 

 

Таблица 5.

Для упрощения программной реализации примера, рекомендуется преобразовать исходный автомат Мили в эквивалентный по вычислительной мощности автомат Мура. Для этого требуется произвести расщепление тех состояний - sn, которым соответствует более одной функции выхода - λ (sn, xn).

 

x0

x1

Расщепление состояния S

 

 

 

 

s0 - Neutral

y3

y3

Не требуется

 

 

 

 

s1 - Pity

y2

y2

Не требуется

 

 

 

 

s2 - Anger

y0

y1

s2 = {s2, s4}

 

 

 

 

s3 - Joy

y4

y5

s3 = {s3, s5}

 

 

 

 

Таблица 6.

Из таблицы преобразования видно, что произошло формирование двух новых состояний: {s4, s5}. Ранее в состоянии гнева – s2, отец либо ругал сына – y1, либо использовал ремень – y0, а в состоянии радости – s3, либо просто радовался – y4, либо ликовал – y5. Таким образом, функциональность можно распределить по состояниям согласно соответствия силы эмоциональной экспрессии состояния и выполняемого действия.

258

Например, s2-Гнев = {s2-Сильный Гнев, s4-Гнев}, s3-Радость = {s3-Радость, s5-Сильная Радость}. Соответственно: В

состоянии «простого» гнева - s4-Гнев, можно ругать сына - y1 - ругать сына, а в состоянии сильного гнева - s2-Сильный Гнев, можно использовать ремень - y0 - брать ремень. В состоянии «простой» радости - s3-Радость, можно радоваться - y4 - радоваться, а в состоянии сильной радости - s5-Сильная Радость, можно ликовать - y5 - ликовать. Представим новый автомат таблично.

Таблица 7 - определяет функцию переходов автомата из одного состояния в другое.

δ

2

5

 

 

 

s0 - Neutral

s1

s3

 

 

 

s1 - Pity

s4

s0

 

 

 

s2 - Strong Anger

s2

s0

 

 

 

s3 - Joy

s1

s5

 

 

 

s4 - Anger

s2

s0

 

 

 

s5 - Strong Joy

s1

s5

 

 

 

Таблица 7. (Функции переходов - δ (sn, xn))

Таблица 8 - определяет функцию выходов.

λ

2

 

5

 

 

 

 

s0 - Neutral

y2 - успокаивать сына

 

y4 - радоваться

 

 

 

 

s1 - Pity

y1 - ругать сына

 

y3 - надеяться

 

 

 

 

s2 - Strong Anger

y0 - брать ремень

 

y3 - надеяться

 

 

 

 

s3 - Joy

y2 - успокаивать сына

 

y5 - ликовать

 

 

 

 

s4 - Anger

y0 - брать ремень

 

y3 - надеяться

 

 

 

 

s5 - Strong Joy

y2 - успокаивать сына

 

y5 - ликовать

 

 

 

 

 

Таблица 8. (Функции выходов - λ (sn, xn))

 

259

Теперь представим автомат Мура в виде графа (в сравнении с автоматом Мили):

Автомат Мили

Автомат Мура

Граф 4.

Получившийся автомат Мура имеет:

шесть состояний в которых может пребывать отец, S = { s0, s1, s2, s3, s4, s5 }, где:

s0 – Neutral (Нейтральное состояние)

s1 – Pity (Жалость)

s2 – Strong Anger (Сильный Гнев)

s3 – Joy (Радость)

s4 – Anger (Гнев)

s5 – Strong Joy (Сильная Радость)

два входных сигнала – оценки полученные сыном в школе X = { x0, x1 }, где:

x0 = 2

x1 = 5

шесть выходных сигналов, т.е., действий отца Y = { y0, y1, y2, y3, y4, y5 }, где:

y0 - брать ремень;

y1 - ругать сына;

y2 - успокаивать сына;

y3 - надеяться;

y4 - радоваться;

y5 - ликовать;

Построив программу, реализующую логику данного конечного автомата и добавив активные устройства (звуковые динамики и механизм-манипулятор для управления пространственным положением ремня при обработке мягких тканей задней и латеральных поверхностей таза), можно воспитание своего сына поручить компьютеру.

260

Предлагается более подробно рассмотреть программную реализацию автомата Мура, имитирующего поведение умного отца.

Рассмотрим класс Father. Объект класса Father может находиться в одном из шести состояний:

NeutralState (Нейтральное состояние), PityState (Жалость), JoyState (Радость),

StrongJoyState (Сильная Радость), AngerState (Гнев), StrongAngerState (Сильный Гнев). Все классы состояний являются производными от базового абстрактного класса State. Объект типа Father хранит ссылку на определенный объект состояния.

public class Father

{

internal State State { get; set; }

public Father()

{

State = new NeutralState();

}

public void FindOut(Mark mark)

{

State.HandleMark(this, mark);

}

}

Объект класса Father делегирует все запросы (вызовы метода HandleMark()), объекту типа State, ссылка на который храниться в автосвойстве State.

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

internal abstract class State

{

internal virtual void HandleMark(Father father, Mark mark)

{

ChangeState(father, mark);

}

protected abstract void ChangeState(Father father, Mark mark);

}

В подклассах класса State реализовано поведение, характерное для каждого конкретного состояния.

261

// Нейтральное состояние (S0) internal class NeutralState : State

{

internal NeutralState()

{

Console.WriteLine("Отец в нейтральном состоянии:"); Hope();

}

protected override void ChangeState(Father father, Mark mark)

{

switch (mark)

{

case Mark.Two:

{

father.State = new PityState(); // S1 break;

}

case Mark.Five:

{

father.State = new JoyState(); // S3 break;

}

}

}

private void Hope() // y3

{

Console.WriteLine("Надеется на хорошие оценки.");

}

}

// Состояние жалости (S1) internal class PityState : State

{

internal PityState()

{

Console.WriteLine("Отец в состоянии жалости:"); Calm();

}

protected override void ChangeState(Father father, Mark mark)

{

switch (mark)

{

case Mark.Two:

{

father.State = new AngerState(); // S4 break;

}

case Mark.Five:

{

father.State = new NeutralState(); // S0 break;

}

}

}

private void Calm() // y2

{

262

Console.WriteLine("Успокаивает сына.");

}

}

// Состояние сильного гнева (S2) internal class StrongAngerState : State

{

internal StrongAngerState()

{

Console.WriteLine("Отец в состоянии сильного гнева:"); BeatBelt();

}

protected override void ChangeState(Father father, Mark mark)

{

switch (mark)

{

case Mark.Two:

{

father.State = new StrongAngerState(); // S2 break;

}

case Mark.Five:

{

father.State = new NeutralState(); // S0 break;

}

}

}

private void BeatBelt() // y0

{

Console.WriteLine("Бьет сына ремнем.");

}

}

// Состояние радости (S3) internal class JoyState : State

{

internal JoyState()

{

Console.WriteLine("Отец в состоянии радости:"); Joy();

}

protected override void ChangeState(Father father, Mark mark)

{

switch (mark)

{

case Mark.Two:

{

father.State = new PityState(); // S1 break;

}

case Mark.Five:

{

father.State = new StrongJoyState(); // S5 break;

}

}

263

}

private void Joy() // y4

{

Console.WriteLine("Радуется успехам сына.");

}

}

// Состояние гнева (S4)

internal class AngerState : State

{

internal AngerState()

{

Console.WriteLine("Отец в состоянии гнева:"); Scold();

}

protected override void ChangeState(Father father, Mark mark)

{

switch (mark)

{

case Mark.Two:

{

father.State = new StrongAngerState(); // S2 break;

}

case Mark.Five:

{

father.State = new NeutralState(); // S0 break;

}

}

}

private void Scold() // y1

{

Console.WriteLine("Ругает сына.");

}

}

// Состояние сильной радости (S5) internal class StrongJoyState : State

{

internal StrongJoyState()

{

Console.WriteLine("Отец в состоянии сильной радости:"); Exult();

}

protected override void ChangeState(Father father, Mark mark)

{

switch (mark)

{

case Mark.Two:

{

father.State = new PityState(); // S1 break;

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]