2012-02-06 3 views
0

Без государственного образцаНепонимание государственного образца

public static void main(String[] args) { 
    Context c = new Context(); 
    for (int i = 0; i < 10; i++) 
     c.someMethod(); 
} 

static class Context { 
    public static final int STATE_A = 0; 
    public static final int STATE_B = 1; 

    private int state = STATE_A; 

    public void someMethod() { 
     switch (state) { 
     case STATE_A: 
      System.out.println("StateA.SomeMethod"); 
      state = STATE_B; 
      break; 
     case STATE_B: 
      System.out.println("StateB.SomeMethod"); 
      state = STATE_A; 
      break; 
     default: 
      break; 
     } 
    } 
} 

государственного образца

public static void main(String[] args) { 
     Context context = new Context(); 
     context.setState(new State1()); 
     for (int i = 0; i < 10; i++) 
      context.someMethod(); 
    } 

    static class Context { 
     State state; 

     void setState(State state) { 
      this.state = state; 
     } 

     void someMethod() { 
      state.someMethod(); 
      if (state instanceof State1) { 
       state = new State2(); 
      } else { 
       state = new State1(); 
      } 
     } 
    } 

    static interface State { 
     void someMethod(); 
    } 

    static class State1 implements State { 
     @Override 
     public void someMethod() { 
      System.out.println("StateA.SomeMethod"); 
     } 
    } 

    static class State2 implements State { 
     @Override 
     public void someMethod() { 
      System.out.println("StateB.SomeMethod"); 
     } 
    } 

В первом случае мы имеем только один объект, но в другом мы создаем новый объект каждый раз, когда мы называем someMethod() метод.

  1. Это правильное понимание рисунка?
  2. Как я могу решить эту проблему, чтобы не создавать так много объектов?
  3. Что еще мне нужно знать об этом шаблоне?
+1

Ваш первый пример имеет только два состояния. В более крупном примере 'someMethod()' будет очень громоздким. Не беспокойтесь о создании небольших, короткоживущих объектов. Сборщик мусора справляется с этим очень хорошо. Если создание объекта действительно становится проблемой, просто держите экземпляр каждого класса состояний в Map или List или (ab) используйте для этого перечисление enum. – Barend

+0

Спасибо за ваш ответ. – drifter

ответ

2

Ну вы можете сделать лучше:

Вы не должны проверить InstanceOf, чтобы перейти к новому состоянию.
Каждое состояние должно быть в состоянии перейти к следующему, как только оно запустится (Образец: даже не пытался скомпилировать).

Пример:

class Context { 
    State state;     

    public Context(){ 
     state = STATE1;//Starting state 
    } 

    void someMethod() { 
      state.someMethod(this); //Which is it?State1 or state 2??? 
    } 

} 

public interface States { 
    public static final State STATE1 = new State1(); 
    public static final State STATE2 = new State2(); 
    //more states here 

} 

class State1 implements State { 
    @Override   
     public void someMethod(Context ctx) {    
     System.out.println("StateA.SomeMethod"); 
     ctx.setState(STATE2); //advance to next state   
    } 
} 

class State2 implements State { 
    @Override   
    public void someMethod(Context ctx) {    
    System.out.println("StateB.SomeMethod"); 
    ctx.setState(STATE1); //advance to next state (back to state 1)   
    } 
} 
+0

Вы также можете сделать State1 внутренним классом внутри контекста. Таким образом, вам не нужно будет передавать ссылку на Context внутри someMethod() – JohnnyK

+0

. Вы правы. Только для двух состояний, которые также будут работать – Cratylus

2

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

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

+0

Я думаю, что описанную вами проблему можно решить, сохраняя контекстную информацию/состояние с помощью states.Ie каждое состояние связано с объектом данных контекста, который предоставляет достаточную информацию для определения следующего состояния. Ответственность за предоставление контекста конечному пользователю предоставляется. – Cratylus

+0

Ну, использование контекста на самом деле ничего не меняет. Как вы повторно используете объект состояния в двух разных регионах? –

+0

Не уверен, что я последую за вами сейчас – Cratylus

Смежные вопросы