Мое текущее понимание шаблона разработки состояния - в основном это:
Инкапсулируйте все поведение объекта в конкретном состоянии в объекте. Делегат запрашивает к "Текущему" объекту состояния.
Мой вопрос: Что лучший способ состоит в том, чтобы обработать изменения состояния? В моем случае вероятно, что "Текущий" объект состояния будет тем, который решает к тому, к чему другому состоянию мы должны перейти. Я думал о 2 способах реализовать это:
Методы объектов состояния могут возвратить некоторое конкретное значение, которое означает, что "я запрашиваю изменение состояния". Основной объект может затем запросить текущее состояние для того, к какому новому состоянию мы должны перейти, звонить ChangeState()
, и затем направьте исходный запрос к новому состоянию.
Сам объект состояния может звонить ChangeState()
на родителе и затем нем передают запрос, который вызвал изменение состояния на новом объекте.
Сценарий 2 имеет преимущество, что основной объект должен только когда-либо делегировать запросы к "Текущему" состоянию (это внутренне обработает любые необходимые изменения состояния). Это также, возможно, немного менее очевидно.
Я надеюсь, там известны лучшие способы обработать этот сценарий. Что Вы думаете?
Я думаю, вы, возможно, ограничиваете себя, чтобы думать только с точки зрения объектов, реализующих паттерн государства (объект контекста и объекты государства). Это не так, и есть другие вовлеченные объекты (клиенты). Возможно, что клиент, который содержит ссылку на объект контекста, должен иметь ответственность за переходное состояние.
Рассмотрим этот пример:
// Paintbrush is the context object
class Paintbrush {
// The State object, ColourState would be the abstraction
private ColourState colourState;
// ... other class stuff
public paint() {
// Delegation to the state object
this.colourState.paintInYourSpecificColour();
}
public void setColourState(ColourState newState) {
this.colourState = newState;
}
}
Это должно быть достаточно реализации для объекта контекста. Обратите внимание, что ни один Colourstate
, ни класс Paintbrush
обладает какими-либо знаниями состояния переходов. Это означает уменьшение количества обязанностей, а также обеспечить более гибкий дизайн.
В основном, изменения государства могут быть ответственность за вызывающий класс. Как это на самом деле достигнуто в коде, это деталь реализации, но важно отметить, что ни один объект контекста, ни государственный объект не несет ответственности за переходное состояние.
Я пытаюсь убедиться, что я не пользуюсь аргументом соловянка, но я буду продолжать бегать с примером. Скажите в разных точках, которые вы хотели нарисовать разные узоры, и используемые цвета должны быть в определенном порядке, ваш клиент решит, когда изменить состояние, как это:
public void paintRainbow() {
paintbrush.setColourState(new RedColourState());
// do painting...
// Change state to next colour
paintbrush.setColourState(new OrangeColourState());
// Chane state again, and so on...
}
Вы могут имеют порядок цветов указано государством или объектом контекста, то есть. У подкласса Paintbrush
называется RainbowpaintBrush
, и он выбрал бы следующий цвет. Или ваши государственные объекты могли выбрать следующее состояние, в этом случае вы должны иметь RedrawoClourState
, который знал следующее государство OrangerainbobleColourstate
и так далее. Но проблема с обоими этими примерами состоит в том, что вы должны войти и изменять (по расширению) как контекстом, так и объекты состояния для достижения другого набора переходов. Однако, если не знают переходов, и это ответственность за вызовов класса, это может быть сделано без изменения состояния или объекта контекста. Т.е.
public void paintChessboard() {
paintbrush.setColourState(blackColourState);
// do painting...
// change state
paintbrush.setColourState(whiteColourState);
// etc...
}
Это упрощенный пример, но он обычно проводит.
Быстрый прочитанный пример википедии состояния показывает, что отдельные состояния имеют знания о следующем состоянии, поэтому я не думаю, что это недействительно. Я думаю, что в целом это компромисс, где вы хотите, чтобы контроль был, и как это будет вписаться в вашу проблему. Это то, как использование объектов бетонных состояний к переходу вписывается в мою пример хромания:
public class RedRainbowColourState implements ColourState {
public void doPaint(Paintbrush paintbrush) {
// do painting
ColourState nextStateInRainbow = new OrangePaintbrushColourState();
paintbrush.setColourState(nextStateInRainbow);
}
, но обратите внимание на взрыв классов состояний, которые потребуются для перехода через все государства, используемые таким образом. Однако преимущество здесь заключается в том, что клиент может быть освобожден от ответственности и знания о том, как создать отдельные государства. В вашей ситуации, это может быть лучшим способом перехода.
Чтобы обобщить, вы можете позволить отдельным состояниям выполнять переход или даже объект контекста. Другой выбор - позволить клиенту обрабатывать переходы состояния.
Я предпочитаю, чтобы метод состояния возвращал новый объект состояния (он уменьшает связь и более соответствует принципам S.O.L.I.D.).
Вот пример (эта идея используется в реальном проекте):
class ExternalContext {
//...
}
class Entity
{
public Entity(ExternalContext context)
{
//Creating current state with factory method
state = EntityState.Create(context);
}
public void ChangeEntity(ExternalContext context)
{
state = state.Change(context);
}
private EntityState state;
}
abstract class EntityState
{
public abstract EntityState Change(ExternalContext externalContext);
public static EntityState Create(ExternalContext externalContext);
}
class EntityState1 : EntityState {
public override EntityState Change(ExternalContext externalContext) {
//..
}
}