CodeLAB
на главную карта сайта обратная связь
каталог | задачи | паттерны | исходники | стат | форумы | ссылки
 гость
искать в
Главная >> Каталог задач >> Паттерны >> Поведения >> Состояние (State)

<< назад
распечатать обсудить >>


Состояние (State)
реализации: java, количество: 5

Aвтор: this
Дата: 06.10.2007
Просмотров: 54605
Рейтинг: 0/0,0(0)
+
реализации(исходники) +добавить

Имя

«Паттерн
State» оригинал codelab.ru codelab.ru источник

Состояние - паттерн поведения объектов, задающий разную функциональность в зависимости от внутреннего состояния объекта. codelab.ru оригинал источник codelab.ru

Условия, Задача, Назначение

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

Мотивация

Рассмотрим класс TCPConnection, с помощью которого представлено сетевое соединение. Объект этого класса может находиться в одном из нескольких состояний: Established (установлено), Listening (прослушивание), Closed (закрыто). Когда объект TCPConnection получает запросы от других объектов, то в зависимости от текущего состояния он отвечает по-разному. Например, ответ на запрос Open (открыть) зависит от того, находится ли соединение в состоянии Closed или Established. Паттерн состояние описывает, каким образом объект TCPConnection может вести себя по-разному, находясь в различных состояниях. источник codelab.ru codelab.ru оригинал
Основная идея этого паттерна заключается в том, чтобы ввести абстрактный класс TCPState для представления различных состояний соединения. Этот класс объявляет интерфейс, единый для всех классов, описывающих различные рабочие codelab.ru codelab.ru оригинал источник

состояния. В этих подклассах TCPState реализуется поведение, специфичное для конкретного состояния. Например, в классах TCPEstablished и TCPClosed реализовано поведение, характерное для состояний Established и Closed соответственно. источник codelab.ru оригинал codelab.ru

codelab.ru источник оригинал codelab.ru

Класс TCPConnection хранит у себя объект состояния (экземпляр подкласса TCPState), представляющий текущее состояние соединения, и делегирует все зависящие от состояния запросы этому объекту. TCPConnection использует свой экземпляр подкласса TCPState достаточно просто: вызывая методы единого интерфейса TCPState, только в зависимости от того какой в данный момент хранится конкретный подкласс TCPState-а – результат получается разным, т.е. в реальности выполняются операции, свойственные только данному состоянию соединения. оригинал источник codelab.ru codelab.ru

А при каждом изменении состояния соединения TCPConnection изменяет свой объект-состояние. Например, когда установленное соединение закрывается, TCPConnection заменяет экземпляр класса TCPEstablished экземпляром TCPClosed. codelab.ru оригинал источник codelab.ru

Признаки применения, использования паттерна Состояние (State)

Используйте паттерн состояние в следующих случаях: codelab.ru оригинал codelab.ru источник
  1. Когда поведение объекта зависит от его состояния и при этом должно изменяться во время выполнения. источник codelab.ru оригинал codelab.ru
  2. Когда в коде операций встречаются состоящие из многих ветвей условные операторы, в которых выбор ветви зависит от состояния. Обычно в таком случае состояние представлено перечисляемыми константами. Часто одна и та же структура условного оператора повторяется в нескольких операциях.Паттерн состояние предлагает поместить каждую ветвь в отдельный класс. Это позволяет трактовать состояние объекта как самостоятельный объект, который может изменяться независимо от других. источник оригинал codelab.ru codelab.ru

Решение

источник оригинал codelab.ru codelab.ru

codelab.ru codelab.ru оригинал источник

Участники паттерна Состояние (State)

оригинал источник codelab.ru codelab.ru

  1. Context (TCPConnection) – контекст.
    Определяет единый интерфейс для клиентов.
    Хранит экземпляр подкласса ConcreteState, которым определяется текущее состояние. codelab.ru codelab.ru источник оригинал
  2. State (TCPState) – состояние.
    Определяет интерфейс для инкапсуляции поведения, ассоциированного с конкретным состоянием контекста Context. источник codelab.ru оригинал codelab.ru
  3. Подклассы ConcreteState (TCPEstablished, TCPListen, TCPClosed) - конкретное состояние.
    Каждый подкласс реализует поведение, ассоциированное с некоторым состоянием контекста Context. codelab.ru источник codelab.ru оригинал

Схема использования паттерна Состояние (State)

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

При этом либо Context, либо сами подклассы ConcreteState могут решить, при каких условиях и в каком порядке происходит смена состояний. codelab.ru оригинал источник codelab.ru

Вопросы, касающиеся реализации паттерна Состояние (State)

Вопросы, касающиеся реализации паттерна State: codelab.ru codelab.ru оригинал источник

  1. Что определяет переходы между состояниями.
    Паттерн состояние ничего не сообщает о том, какой участник определяет условия (критерии) перехода между состояниями. Если критерии зафиксированы, то их можно реализовать непосредственно в классе Context. Однако в общем случае более гибкий и правильный подход заключается в том, чтобы позволить самим подклассам класса State определять следующее состояние и момент перехода. Для этого в класс Context надо добавить интерфейс, позволяющий из объектов State установить его состояние.
    Такую децентрализованную логику переходов проще модифицировать и расширять – нужно лишь определить новые подклассы State. Недостаток децентрализации в том, что каждый подкласс State должен «знать» еще хотя бы об одном подклассе другого состояния (на которое собственно он и сможет переключить текущее состояние), что вносит реализационные зависимости между подклассами. codelab.ru оригинал codelab.ru источник
    источник оригинал codelab.ru codelab.ru
  2. Табличная альтернатива.
    Существует еще один способ структурирования кода, управляемого сменой состояний. Это принцип конечного автомата. Он использует таблицу для отображения входных данных на переходы между состояниями. С ее помощью можно определить, в какое состояние нужно перейти при поступлении некоторых входных данных. По существу, тем самым мы заменяем условный код поиском в таблице.
    Основное преимущество автомата – в его регулярности: для изменения критериев перехода достаточно модифицировать только данные, а не код. Но есть и недостатки:
    - поиск в таблице часто менее эффективен, чем вызов функции,
    - представление логики переходов в однородном табличном формате делает критерии менее явными и, стало быть, более сложными для понимания,
    - обычно трудно добавить действия, которыми сопровождаются переходы между состояниями. Табличный метод учитывает состояния и переходы между ними, но его необходимо дополнить, чтобы при каждом изменении состоянии можно было выполнять произвольные вычисления.
    Главное различие между конечными автоматами на базе таблиц и Паттерн состояние можно сформулировать так: Паттерн состояние моделирует поведение, зависящее от состояния, а табличный метод акцентирует внимание на определении переходов между состояниями. codelab.ru codelab.ru источник оригинал
    codelab.ru источник codelab.ru оригинал
  3. Создание и уничтожение объектов состояния.
    В процессе разработки обычно приходится выбирать между:
    - созданием объектов состояния, когда в них возникает необходимость, и уничтожением сразу после использования,
    - созданием их заранее и навсегда.

    Первый вариант предпочтителен, когда заранее неизвестно, в какие состояния будет попадать система, и контекст изменяет состояние сравнительно редко. При этом мы не создаем объектов, которые никогда не будут использованы, что существенно, если в объектах состояния хранится много информации. Когда изменения состояния происходят часто, поэтому не хотелось бы уничтожать представляющие их объекты (ибо они могут очень скоро понадобиться вновь), следует воспользоваться вторым подходом. Время на создание объектов затрачивается только один раз, в самом начале, а на уничтожение – не затрачивается вовсе. Правда, этот подход может оказаться неудобным, так как в контексте должны храниться ссылки на все состояния, в которые система теоретически может попасть. codelab.ru оригинал codelab.ru источник
    оригинал источник codelab.ru codelab.ru
  4. Использование динамического изменения.
    Варьировать поведение по запросу можно, меняя класс объекта во время выполнения, но в большинстве объектно-ориентированных языков это не поддерживается. Исключение составляет Perl, JavaScript и другие основанные на скриптовом движке языки, которые предоставляют такой механизм и, следовательно, поддерживают Паттерн состояние напрямую. Это позволяет объектам варьировать поведение путем изменения кода своего класса. codelab.ru codelab.ru оригинал источник
    codelab.ru codelab.ru оригинал источник

Результаты

Результаты использования паттерна состояние: codelab.ru codelab.ru оригинал источник
  1. Локализует зависящее от состояния поведение.
    И делит его на части, соответствующие состояниям. Паттерн состояние помещает все поведение, ассоциированное с конкретным состоянием, в отдельный объект. Поскольку зависящий от состояния код целиком находится в одном из подклассов класса State, то добавлять новые состояния и переходы можно просто путем порождения новых подклассов.
    Вместо этого можно было бы использовать данные-члены для определения внутренних состояний, тогда операции объекта Context проверяли бы эти данные. Но в таком случае похожие условные операторы или операторы ветвления были бы разбросаны по всему коду класса Context. При этом добавление нового состояния потребовало бы изменения нескольких операций, что затруднило бы сопровождение. Паттерн состояние позволяет решить эту проблему, но одновременно порождает другую, поскольку поведение для различных состояний оказывается распределенным между несколькими подклассами State. Это увеличивает число классов. Конечно, один класс компактнее, но если состояний много, то такое распределение эффективнее, так как в противном случае пришлось бы иметь дело с громоздкими условными операторами.
    Наличие громоздких условных операторов нежелательно, равно как и наличие длинных процедур. Они слишком монолитны, вот почему модификация и расширение кода становится проблемой. Паттерн состояние предлагает более удачный способ структурирования зависящего от состояния кода. Логика, описывающая переходы между состояниями, больше не заключена в монолитные операторы if или switch, а распределена между подклассами State. При инкапсуляции каждого перехода и действия в класс – состояние становится полноценным объектом. Это улучшает структуру кода и проясняет его назначение. оригинал codelab.ru источник codelab.ru
  2. Делает явными переходы между состояниями.
    Если объект определяет свое текущее состояние исключительно в терминах внутренних данных, то переходы между состояниями не имеют явного представления; они проявляются лишь как присваивания некоторым переменным. Ввод отдельных объектов для различных состояний делает переходы более явными. Кроме того, объекты State могут защитить контекст Context от рассогласования внутренних переменных, поскольку переходы с точки зрения контекста – это атомарные действия. Для осуществления перехода надо изменить значение только одной переменной (объектной переменной State в классе Context), а не нескольких. источник codelab.ru оригинал codelab.ru
  3. Объекты состояния можно разделять.
    Если в объекте состояния State отсутствуют переменные экземпляра, то есть представляемое им состояние кодируется исключительно самим типом, то разные контексты могут разделять один и тот же объект State. Когда состояния разделяются таким образом, они являются, по сути дела, приспособленцами (см. паттерн-приспособленец), у которых нет внутреннего состояния, а есть только поведение. codelab.ru оригинал codelab.ru источник

Пример

Рассмотрим реализацию примера из раздела «Мотивация», т.е. построение некоторой простенькой архитектуры TCP соединения. Это упрощенный вариант протокола TCP, в нем, конечно же, представлен не весь протокол и даже не все состояния TCP-соединений. codelab.ru codelab.ru оригинал источник

Прежде всего определим класс TCPConnection, который предоставляет интерфейс для передачи данных и обрабатывает запросы на изменение состояния: TCPConnection. codelab.ru оригинал источник codelab.ru

В переменной-члене state класса TCPConnection хранится экземпляр класса TCPState. Этот класс дублирует интерфейс изменения состояния, определенный в классе TCPConnection. оригинал codelab.ru codelab.ru источник
  источник оригинал codelab.ru codelab.ru
TCPConnection делегирует все зависящие от состояния запросы хранимому в state экземпляру TCPState. Кроме того, в классе TCPConnection существует операция ChangeState, с помощью которой в эту переменную можно записать указатель на другой объект TCPState. Конструктор класса TCPConnection инициализирует state указателем на состояние-закрытия TCPClosed (мы определим его ниже). источник codelab.ru codelab.ru оригинал
  источник codelab.ru оригинал codelab.ru
Каждая операция TCPState принимает экземпляр TCPConnection как параметр, тем самым, позволяя объекту TCPState получить доступ к данным объекта TCPConnection и изменить состояние соединения. codelab.ru codelab.ru источник оригинал
В классе TCPState реализовано поведение по умолчанию для всех делегированных ему запросов. Он может также изменить состояние объекта TCPConnection посредством операции ChangeState. TCPState располагается в том же пакете, что и TCPConnection, поэтому также имеет доступ к этой операции: TCPState. codelab.ru источник оригинал codelab.ru
  источник оригинал codelab.ru codelab.ru
В подклассах TCPState реализовано поведение, зависящее от состояния. Соединение TCP может находиться во многих состояниях: Established (установлено), Listening (прослушивание), Closed (закрыто) и т.д., и для каждого из них есть свой подкласс TCPState. Для простоты подробно рассмотрим лишь 3 подкласса - TCPEstablished, TCPListen и TCPClosed. codelab.ru оригинал codelab.ru источник
  оригинал codelab.ru codelab.ru источник
В подклассах TCPState реализуется зависящее от состояния поведение для тех запросов, которые допустимы в этом состоянии. codelab.ru оригинал источник codelab.ru
Поскольку в них нет никакого локального состояния – их можно разделять, т.е. сделать одиночками и иметь только по одному экземпляру каждого класса и создавать обращением к статической операции Instance: TCPEstablished, TCPListen, TCPClosed. оригинал codelab.ru codelab.ru источник
  codelab.ru codelab.ru оригинал источник
После выполнения специфичных для своего состояния действий эти операции codelab.ru codelab.ru оригинал источник
вызывают ChangeState для изменения состояния объекта TCPConnection. У него же самого нет никакой информации о протоколе TCP. Именно подклассы TCPState определяют переходы между состояниями и действия, диктуемые протоколом. источник codelab.ru codelab.ru оригинал
codelab.ru оригинал codelab.ru источник

Известные применения паттерна Состояние (State)

Ральф Джонсон и Джонатан Цвейг характеризуют паттерн состояние и описывают его применительно к протоколу TCP.
Наиболее популярные интерактивные программы рисования предоставляют «инструменты» для выполнения операций прямым манипулированием. Например, инструмент для рисования линий позволяет пользователю щелкнуть в произвольной точке мышью, а затем, перемещая мышь, провести из этой точки линию. Инструмент для выбора позволяет выбирать некоторые фигуры. Обычно все имеющиеся инструменты размещаются в палитре. Работа пользователя заключается в том, чтобы выбрать и применить инструмент, но на самом деле поведение редактора варьируется при смене инструмента: посредством инструмента для рисования мы создаем фигуры, при помощи инструмента выбора - выбираем их и т.д. источник оригинал codelab.ru codelab.ru

Чтобы отразить зависимость поведения редактора от текущего инструмента, можно воспользоваться паттерном состояние. источник codelab.ru оригинал codelab.ru
Можно определить абстрактный класс Tool, подклассы которого реализуют зависящее от инструмента поведение. Графический редактор хранит ссылку на текущий объект Tool и делегирует ему поступающие запросы. При выборе инструмента редактор использует другой объект, что приводит к изменению поведения. codelab.ru codelab.ru оригинал источник
Данная техника используется в каркасах графических редакторов HotDraw и Unidraw. Она позволяет клиентам легко определять новые виды инструментов. В HotDraw класс DrawingController переадресует запросы текущему объекту Tool. В Unidraw соответствующие классы называются Viewer и Tool. На приведенной ниже диаграмме классов схематично представлены интерфейсы классов Tool и DrawingController: источник оригинал codelab.ru codelab.ru

codelab.ru оригинал источник codelab.ru

Описанный Джеймсом Коплиеном прием конверт-письмо (EnvelopeLetter) также относится к паттерну состояние. Техника конверт-письмо – это способ изменить класс объекта во время выполнения. Паттерн состояние является частным случаем, в нем акцент делается на работу с объектами, поведение которых зависит от состояния. codelab.ru codelab.ru оригинал источник
источник codelab.ru codelab.ru оригинал
codelab.ru оригинал источник codelab.ru

Родственные паттерны

Паттерн приспособленец подсказывает, как и когда можно разделять объекты класса State. оригинал codelab.ru источник codelab.ru
Объекты класса State часто бывают одиночками. codelab.ru codelab.ru источник оригинал
codelab.ru codelab.ru источник оригинал
источник codelab.ru оригинал codelab.ru
оригинал источник codelab.ru codelab.ru


Реализации: java(5)   +добавить реализацию

1) TCPConnection.java, code #517[автор:this]
2) TCPState.java, code #518[автор:this]
3) TCPEstablished.java, code #519[автор:this]
4) TCPListen.java, code #520[автор:this]
5) TCPClosed.java, code #521[автор:this]


<< назад наверх
распечатать обсудить >>

 
каталог | задачи | паттерны | исходники | стат | форумы | карта сайта | контакты | ссылки 
© 2000-2017 CodeLAB Group
  Все права защищены
Страница сгенерирована за 0.041516 секунд
Количество запросов к БД: 14, gzip: 18.5kb/83.3kb(78%)