coder25 coder25 - 1 month ago 7
Java Question

State pattern java

I am learning design pattern in java

I was doing through some of links.I am trying to design a washing machine by state pattern

I have a query regarding the implementation of state design pattern

public interface State {

public void openLid();
public void closeLid();
public void start();
public void stop();
public void washing();
}

public class Idle implements State{
//implementing overidden methods
.......

}

public class Washing implements State {
//implementing overidden methods
.......
}


public class WashingMachine {
State state;

public WashingMachine(State state) {
this.state = new Idle();
}

public State getState() {
return state;
}

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

}


I want to know when switching between state between idle to washing the implementation there can be two ways which is saw over net

1.WashingMachine class implements State interface and switch state from Idle to washing or vice versa based on some condition

2.Idle and Washing class has WashingMachine as member variable.

Please any one can suggest I am a bit confused about the implementation part.

Answer

Before addressing your question, I prefer reviewing the idea of the pattern and propose you some little modifications in your code.

State pattern allows an object to alter its behavior when its internal state changes.

In your case, Idle and Washing are good candidates as states and WashingMachine a good candidate to bear the state object.

However, three remarks :

1) methods offered by state to its client should be some behaviors or if you prefer some actions which implementations differ according to under which state the object is.

In your declaration :

public interface WashingMachineState {    
   public void openLid();
   public void closeLid();
   public void start();
   public void stop();
   public void washing();
  } 

washing() has no sense because it is not a action but a state.
I imagine that it is the start() operation which should change the state from idle to washing.
If it can be helpful, you can be more precise in the actions provided by the state.

In order not to repeat at each time the object with a state, from now, I will refer the object with the state as the context.
In your case, the context is WashingMachine.

2) in the state pattern, the logic is that the context performs some processings which behavior change according to the current state. To achieve that, the context delegates its processings to its current state instance.
It avoid having many if - else if in the context (for each processing), and it allows also to reduce the complexity of the context because when you use state pattern, you get families of behaviors : behaviors when we are in this condition (idle state) are located in a specific class, behaviors when we are in that other condition (washing state) are located in another specific class...

So, the processing logic should be located in the subclass state instance.
To achieve that, state instances need the context (here : WashingMachine).
To address this question, you have two ways of doing : 1.storing the context (WashingMachine) in the state instance or 2.passing this as an argument when the context (WashingMachine) delegates to the state the processing.
A stateless processing class should be privileged when possible. So, I propose you to do that. So, when the startWashing() operation is called on a WashingMachine instance, the WashingMachine instance should delegate the processing to state.startWashing() by passing itself such as state.startWashing(this).
So your state should offer as parameter a WashingMachine instance. I propose this interface :

public interface WashingMachineState {    
   public void openLid(WashingMachine machine);
   public void closeLid(WashingMachine machine);
   public void pushStartBtn(WashingMachine machine);
   public void pushStopBtn(WashingMachine machine);
  } 

3) idle and washing states should be completed with a stopping state because it is a state and i suppose that some operations (open the door, push start btn for example...) on the machine should give specific results when the machine is in this state.
Besides, with only two states, you may wonder if the pattern is meaningful.


Now, I can answer to your question.

I want to know when switching between state between idle to washing the implementation there can be two ways which is saw over net

1.WashingMachine class implements State interface and switch state from Idle to washing or vice versa based on some condition

2.Idle and Washing class has WashingMachine as member variable.

First solution (without implementing State interface) is better since as explained previously, states should not store the WashingMachine.
Nevertheless, WashingMachine.changeState() has to be called by state instances. I will give you some details about the implementation.

WashingMachine and WashingMachineState are symmetric in their behaviors. Nevertheless they should not use the same interface since WashingMachineState needs the WashingMachine instance as parameter in its operations.

Your WashingMachine could be :

public class WashingMachine {

   private WashingMachineState state;

   public WashingMachine(WashingMachineState state) {
    this.state =  new Idle();
   }        

   protected  void changeState(WashingMachineState state) {
    this.state = state;      
   }

   public void openLid(){
     state.openLid(this);
   } 

   public void closeLid(){
     state.closeLid(this);         
   } 
   public void pushStartBtn(){
     state.pushStartBtn(this);
   } 

   public void pushStopBtn(){
     state.pushStopBtn(this);
   } 

   public State getState() {
      return state;
   }

 }

Explanations on little modifications on WashingMachine :

  • changeState is more meaningful as setState when using state pattern.

  • changeState(State) could use the protected modifier to decrease the visibility of this method and of course state subclasses should be in the same package than WashingMachine. It is a implementation detail enabled in Java. With other OOP languages, you have other alternatives of course.

Switching between idle to washing should be possible only in the IdleState :

public class IdleState implements State {    
   public void openLid(WashingMachine machine){
       ...
   }
   public void closeLid(WashingMachine machine){
       ...
   }
   public void pushStartBtn(WashingMachine machine){
      //do processing with machine to begin effectively the washing
         ...
      machine.changeState(new WashingState());
   }

   public void pushStopBtn(WashingMachine machine){
       ...
   }
 }