Design Mode-status Mode
To implement a state machine, the common technique of state modeling in an object is to create an instance variable to hold the State value and write the condition code in the method to process different states. Design a rough template as follows
public class TestState{ final static int State1 = 0; final static int State2 = 1; public void dosomething{ if(state = State1) ... if(state = State2)... }
This method will be in a chaotic state when the change request needs to add several states, so that all methods that indicate actions must be modified. It does not follow the principle of "encapsulation change. following this principle, we can try to localize the behavior of each state, so that if we change a state, it will not affect other code. First, we can define a state interface. In this interface, each action in the state chart has a corresponding method ,. Then, implement status classes for each State. These classes are responsible for performing corresponding actions on the corresponding State node. In this way, we can request the old condition code and delegate the actions to the status class. This is the basic idea of the state mode. By encapsulating each State into a class, we will localize any changes that need to be done in the future.
Status mode definition
The State mode allows an object to change its behavior when its internal state changes. The object seems to have modified its class.
In this mode, the status is encapsulated into an independent class and the action is delegated to an object that represents the current status. This means that the action changes with the internal status.
What does "It seem to have modified its class" mean? From the customer's perspective: if the object you use can completely change its behavior, you will feel that this object is actually instantiated from other classes.However, in fact, you know that we are using combinations to create the illusion of class changes by simply referencing different State objects.
Status pattern class diagram
The class diagrams of the Status mode and Policy mode are the same. The differences between the two modes are analyzed below.
Example of a candy machine
Suppose we want to implement a candy machine with JVM. There are five statuses of the candy machine: No 25 cent, 25 cent, sold out, and winner, when the customer performs different operations, the candy machine enters different States under different conditions. The following figure shows the status Conversion Diagram of the candy machine. This State Conversion Diagram is complicated because it is added to a winner state, each time the crank is turned, there will be a 10% chance of a winner. The winner status will issue one more candy.
The code for turning the crank part will be very complicated if we still use conditional judgment to implement this state.
According to the basic idea of the state mode, this candy machine can be implemented in the following three steps:
(1) first, we define a state interface. In this interface, each action of the candy machine has a corresponding method.
(2) The status class is then implemented for each State of the machine. These classes are responsible for machine behavior in the corresponding state.
(3) Finally, we need to delegate the action to the status class.
The corresponding java code is as follows:
?? // State. java package State;/** State interface State */public interface State {public void insertQuarter (); // invest 25 cents in public void ejectQuarter (); // reject 25 cent public void turnCrank (); // rotate the crank public void dispense (); // issue candy} // NoQuarterState. java package State; import State. gumballMachine;/** the status does not have 25 cents, implementing the State interface */public class NoQuarterState implements State {GumballMachine gumballMachine; public NoQuarte RState (GumballMachine gumballMachine) {this. gumballMachine = gumballMachine;} // invest 25 cents in public void insertQuarter () {System. out. println ("You insert a quarter"); gumballMachine. setState (gumballMachine. getHasQuarterState ();} // reject 25 cent public void ejectQuarter () {System. out. println ("You haven't insert a quarter");} // rotate the crank public void turnCrank () {System. out. println ("You turned crank, but you Re's no quarter ");} // issue candy public void dispense () {System. out. println ("You need to pay first") ;}// HasQuarterState. java package State; import java. util. random; import State. gumballMachine;/** with 25 cent status, implemented the State interface */public class HasQuarterState implements State {Random randomWinner = new Random (System. currentTimeMillis (); // first, we add a random number generator to generate the GumballMachine gumballMachine; public Ha SQuarterState (GumballMachine gumballMachine) {this. gumballMachine = gumballMachine;} // invest 25 cents in public void insertQuarter () {System. out. println ("You can not insert anther quarter");} // reject 25 cent public void ejectQuarter () {System. out. println ("Quarter returned"); gumballMachine. setState (gumballMachine. getNoQuarterState ();} // rotate the crank public void turnCrank () {System. out. println ("You turned... "); in T winner = randomWinner. nextInt (10); System. out. println ("winner =" + winner); if (winner = 0) & (gumballMachine. getCount ()> 1) {gumballMachine. setState (gumballMachine. getWinnerState (); // if you win and have enough candy to enter the winnerstate state} else {gumballMachine. setState (gumballMachine. getSoldState (); // otherwise enter the soldstate status} // issue the public void dispense () {System. out. println ("No gumball dispensed") ;}// SoldState. Java package State; import State. gumballMachine;/** the State of the candy sold, implementing the State interface */public class SoldState implements State {GumballMachine gumballMachine; public SoldState (GumballMachine gumballMachine) {this. gumballMachine = gumballMachine;} // invest 25 cents in public void insertQuarter () {System. out. println ("Please wait, we're already giving you a gumball");} // reject 25 cent public void ejectQuarter () {System. out. Println ("Sorry, you have already turn crank");} // rotate the crank public void turnCrank () {System. out. println ("trun twice, doesn't give you anthor gamball! ");} // Issue candy public void dispense () {gumballMachine. releaseBall (); if (gumballMachine. getCount ()> 0) {gumballMachine. setState (gumballMachine. getNoQuarterState ();} else {System. out. println ("Opps, out of gamball! "); GumballMachine. setState (gumballMachine. getSoldOutState () ;}}// SoldOutState. java package State; import State. gumballMachine;/** implements the State interface */public class SoldOutState implements State {GumballMachine gumballMachine; public SoldOutState (GumballMachine gumballMachine) {this. gumballMachine = gumballMachine;} // invest 25 cents in public void insertQuarter () {System. out. println ("You can't insert A quarter, the machine is sold out ");} // reject 25 cent public void ejectQuarter () {// TODO Auto-generated method stub System. out. println ("You can't eject, you haven't inserted a quarter yet");} // rotate the crank public void turnCrank () {// TODO Auto-generated method stub System. out. println ("You turned, but there are no gumbils");} // issue the public void dispense () {// TODO Auto-generated method stub System. ou T. println ("No gumball dispensed") ;}// WinnerState. java package State; import State. gumballMachine;/** the winner State, implementing the State interface */public class WinnerState implements State {GumballMachine gumballMachine; public WinnerState (GumballMachine gumballMachine) {this. gumballMachine = gumballMachine;} // invest 25 cents @ Override public void insertQuarter () {// TODO Auto-generated method stub System. out. println ("Plea Se wait, we're already giving you a gumball ");} // reject 25 cents @ Override public void ejectQuarter () {// TODO Auto-generated method stub System. out. println ("Sorry, you have already turn crank");} // rotate the crank @ Override public void turnCrank () {// TODO Auto-generated method stub System. out. println ("trun twice, doesn't give you anthor gamball! ");} // Issue candy @ Override public void dispense () {// TODO Auto-generated method stub System. out. println (" You're a Winner! You get two gumbils for your quarter "); gumballMachine. releaseBall (); if (gumballMachine. getCount () = 0) {gumballMachine. setState (gumballMachine. getSoldOutState ();} else {gumballMachine. releaseBall (); if (gumballMachine. getCount ()> 0) {gumballMachine. setState (gumballMachine. getNoQuarterState ();} else {System. out. println ("Opps, out of gamball! "); GumballMachine. setState (gumballMachine. getSoldOutState () ;}}// the Java source file GumballMachine in the context environment of the candy machine. java package State; import State. hasQuarterState; import State. noQuarterState; import State. soldOutState; import State. soldState; import State. winnerState; import State. state;/** candy machine context environment interface class GumballMachine */public class GumballMachine {// State instance State soldOutState; State noQuarterState; State HasQuarterState; State soldState; State winnerState; // instance variable state, initialized to the sold-out State state = soldOutState; // records the number of sweets contained in the machine, the starting machine is the int count = 0 without candy loading; // The constructor obtains the initial number of candy and places it in an instance variable count public GumballMachine (int numbergumbils) {// each State creates a State instance soldOutState = new SoldOutState (this); noQuarterState = new NoQuarterState (this); hasQuarterState = new HasQuarterState (this ); soldState = new SoldState (this); winnerS Tate = new WinnerState (this); this. count = numbergumbils; // if there are more than 0 sweets, set the status to NoQuarterState if (numbergumbils> 0) {state = noQuarterState ;}} // obtain the number of sweets in the machine. public int getCount () {return count;} // obtain the sold-out State of candy. public State getSoldOutState () {return soldOutState ;} // get the public State getNoQuarterState () {return noQuarterState;} // get the public State getHasQuarterState () {return hasQ with 25 cents UarterState;} // obtain the State of the sold candy. public State getSoldState () {return soldState;} // obtain the State of the winner. public State getWinnerState () {return winnerState ;} // invest 25 cents in public void insertQuarter () {state. insertQuarter ();} // reject 25 cent public void ejectQuarter () {state. ejectQuarter ();} // rotate the crank public void turnCrank () {state. turnCrank (); state. dispense ();} // sets the public void setState (State state State) {this. state = state;} // A public void releaseBall () {System. out. println ("A gumball comes rolling out of the solt..."); if (count! = 0) {count -- ;}}// test the Java source file GumballMachineTestDrive of the candy machine. java package State;/** candy machine test driver: GumballMachineTestDrive. java */public class GumballMachineTestDrive {/*** @ param args */public static void main (String [] args) {GumballMachine gumballMachine = new GumballMachine (5); System. out. println (gumballMachine); System. out. println ("The current gumball number is:" + gumballMachine. getCount (); System. out. println ("************************************* ***"); gumballMachine. insertQuarter (); gumballMachine. turnCrank (); System. out. println (gumballMachine); System. out. println ("The current gumball number is:" + gumballMachine. getCount (); System. out. println ("************************************* ***"); gumballMachine. insertQuarter (); gumballMachine. turnCrank (); System. out. println (gumballMachine); System. out. println ("The current gumball number is:" + gumballMachine. getCount (); System. out. println ("************************************* ***"); gumballMachine. insertQuarter (); gumballMachine. turnCrank (); System. out. println (gumballMachine); System. out. println ("The current gumball number is:" + gumballMachine. getCount (); System. out. println ("************************************* ***");}}
Add the get method for each status on the candy machine, provide the set method, and then delegate the action to the status class for completion, in this way, we can use the set + get method in the state class to implement the transition between States, such as gumballMachine. setState (gumballMachine. getSoldOutState (); indicates that the modification State enters the soldoutstate state.
Put state conversion in the state class. The disadvantage is that the dependency between States is generated. The getter Method on context is used to minimize the dependency.
Status mode highlights
(1) The customer will not interact with the status. It is the work of context to fully understand the status.
(2) In status mode, each status is transferred by holding the reference of Context.
(3) using the state mode will always increase the number of classes in the design. This is to get the scalability and elasticity of the program. If your code is not disposable, different States may be added in the future, so the design of the state mode is definitely worth it.
(4) The status class can be shared by multiple context instances.
Status mode and Policy Mode Comparison
First, let's look at more similarities between them:
- It is easy to add new states or policies, and they do not need to be modified to use their Context objects.
- They make your Code comply with the OCP principles (the software should be developed for expansion and the modification should be disabled ). In the state mode and Policy mode, the Context object is disabled for modification. You do not need to modify the Context when adding a new State or policy.
- Just as the Context in the state mode has an initial state, the policy mode also has a default policy.
- The State mode encapsulates different behaviors with different states, while the policy mode encapsulates different behaviors with different policies.
- They all rely on subclass to implement relevant behavior
The difference between the two models is that they have different "intentions:
The State mode helps you manage the state of an object. we encapsulate a group of actions in an early state object, and the context behavior can be delegated to one of those States at any time. with the passage of time, the current State Changes in the collection of State objects to reflect the internal state of context. Therefore, the behavior of context also changes. To add a new status, you do not need to modify the original code to add a new status class.
The policy mode allows the Client to select different behaviors. By encapsulating a set of related algorithms, the Client can provide runtime flexibility. The Client can select any algorithm at runtime without changing the Context of the algorithm. Examples of some popular policy patterns are the code that uses algorithms, such as encryption algorithms, compression algorithms, and sorting algorithms. The customer usually takes the initiative to specify the policy object to be combined by context,