state mode
APP Sweepstakes Case
-
If the user will be deducted 50 points for each participation in this activity, the probability of winning is 10%
-
The number of prizes is fixed, and the lottery cannot be drawn after the draw
-
There are four statuses in the event: Lottery can be drawn, Lottery can't be drawn, prizes issued and prizes received
Basic introduction to state mode
-
State Pattern: It is mainly used to solve the problem that objects need to output different behaviors when they are in various state transitions. There is a one-to-one correspondence between states and behaviors, and states can be converted to each other
-
Allows to change behavior when an object's internal state changes, the object appears to change its class
-
The Context class is an environment role and is used to maintain the State instance, which defines the current state
-
State is an abstract state role that defines an interface to encapsulate behavior related to a characteristic interface of Context
-
ConcreteState specific state role, each subclass implements a behavior related to a state of Context
Code
state abstract class
public abstract class State { // Deduction of points - 50 public abstract void deductMoney(); // Did you win a prize? public abstract boolean raffle(); // give out prizes public abstract void dispensePrize(); }
Lottery status
/** * Status available for lottery * @author Administrator * */ public class CanRaffleState extends State { RaffleActivity activity; public CanRaffleState(RaffleActivity activity) { this.activity = activity; } //Points have already been deducted and cannot be deducted any more @Override public void deductMoney() { System.out.println("Points have been deducted"); } //You can draw a lottery. After the lottery is drawn, it will be changed to a new state according to the actual situation. @Override public boolean raffle() { System.out.println("There is a lottery going on, please wait!"); Random r = new Random(); int num = r.nextInt(10); // 10% chance of winning if(num == 0){ // Change the activity status to give out prizes context activity.setState(activity.getDispenseState()); return true; }else{ System.out.println("It's a pity that I didn't win the prize!"); // Change the status to not be able to draw activity.setState(activity.getNoRafflleState()); return false; } } // Prizes cannot be given out @Override public void dispensePrize() { System.out.println("No prizes, no prizes"); } }
Prize distribution completed
/** * Prize distribution completed * Description, when our activity changes to DispenseOutState, the lottery event ends * @author Administrator * */ public class DispenseOutState extends State { // Pass in the activity reference when initializing RaffleActivity activity; public DispenseOutState(RaffleActivity activity) { this.activity = activity; } @Override public void deductMoney() { System.out.println("The prizes have been sent out, please join again next time"); } @Override public boolean raffle() { System.out.println("The prizes have been sent out, please join again next time"); return false; } @Override public void dispensePrize() { System.out.println("The prizes have been sent out, please join again next time"); } }
Activities
/** * Sweepstakes // * * @author Administrator * */ public class RaffleActivity { // state represents the current state of the activity, which is a change State state = null; // Number of prizes int count = 0; // Four attributes, representing four states State noRafflleState = new NoRaffleState(this); State canRaffleState = new CanRaffleState(this); State dispenseState = new DispenseState(this); State dispensOutState = new DispenseOutState(this); //Constructor //1. Initialize the current state to noRafflleState (that is, the state where the lottery cannot be drawn) //2. Initialize the number of prizes public RaffleActivity( int count) { this.state = getNoRafflleState(); this.count = count; } //Deduct points, call deductMoney of the current state public void debuctMoney(){ state.deductMoney(); } //lottery public void raffle(){ // If the current status is that the lottery is successful if(state.raffle()){ //prize collection state.dispensePrize(); } } public State getState() { return state; } public void setState(State state) { this.state = state; } //Please pay attention here, every time you receive a prize, count-- public int getCount() { int curCount = count; count--; return curCount; } public void setCount(int count) { this.count = count; } public State getNoRafflleState() { return noRafflleState; } public void setNoRafflleState(State noRafflleState) { this.noRafflleState = noRafflleState; } public State getCanRaffleState() { return canRaffleState; } public void setCanRaffleState(State canRaffleState) { this.canRaffleState = canRaffleState; } public State getDispenseState() { return dispenseState; } public void setDispenseState(State dispenseState) { this.dispenseState = dispenseState; } public State getDispensOutState() { return dispensOutState; } public void setDispensOutState(State dispensOutState) { this.dispensOutState = dispensOutState; } }
State Mode Notes and Details
-
The code is very readable. The state pattern encapsulates the behavior of each state into a corresponding class
-
Easy maintenance. Delete the if else statements that are easy to cause problems. If you put the behavior of each state into a class, you should judge the current state every time you call the method, which will not only produce a lot of if else statements, and error front
-
Comply with the "open-closed principle". Easy to add and delete states
-
Many classes will be generated. Each state needs a corresponding class. When there are too many states, many classes will be generated, which increases the difficulty of maintenance.
-
Application scenario: When an event or object has many states, the states will be converted to each other, and different behaviors are required for different states, you can consider using the state mode