Introduction to the

The state pattern mainly addresses situations where the conditional expressions governing the state transition of an object are too complex. Complex decision logic can be simplified by moving the decision logic of states into a series of classes that represent different states.

A complex service may have a large number of logical condition judgments such as if and else, which are very dangerous and complex for later maintenance. The state pattern also localizes the behavior associated with a particular state and separates the behavior of different states.

A large number of conditional branching statements can be eliminated and interdependencies can be reduced internally through state transitions

  • Consider: What is the difference between the strategy model, the chain of responsibility model and the state model

The setting

For example, you are involved in baidu network disk development, there are the following common scenarios:

Membership grade permissions
The average user Store photos and files
members Fast download, 5T space…
Super members Automatic video backup, audio and video playback at double speed…

Simple implementation

Permission acquisition class

package design.pattern; import java.util.ArrayList; Public class UserRule {/** * Level 1 Common User 2 Member 3 Super Member */ private Integer level = 1; /** * private ArrayList<String> ruleList = new ArrayList<String>() {{add()"Upload file");
            add("Download file"); }}; public UserRule(Integer level) { this.level = level; } /** * Get permission list ** @return
     */
    public ArrayList<String> getRuleList() {

        if(this.level == 2) {// Member //todo permission rulelist.add ("Speed download");
            ruleList.add("5 t space");
        } else if(this.level == 3) {// Super member //todo permission rulelist.add ("Speed of Light download");
            ruleList.add("10 t space");
            ruleList.add("Automatic backup of small video");
            ruleList.add("Audio and video double speed playback");
        }

        returnruleList; }}Copy the code

Client call:

Integer requestLevel = 3; UserRule userRule = new UserRule(requestLevel); ArrayList<String> ruleList = userRule.getRuleList(); // Print permission system.out.println ("Membership level" + requestLevel + "Permission List :");
for (Object object : ruleList) {
    System.out.println(object);
}
Copy the code

The output:

Member Level 3 Permission list: Upload files download files Light speed download 10 TB space small video automatic backup audio and video playback at double speedCopy the code

Think about:

It seems that our code is simple enough to do a good job of returning permissions by level

We will focus on the business logic of getting permission lists to branch according to different conditions and handling different toDos. If we add more levels, more complex permission calculation methods and so on, the if else will be much bigger.


Just as I said it would be huge, the product came along and gave me the demand for V2.0.

  • Product: recently the market feedback said that our members are not selling very well, now we need to add a little function.
  • I:…
  • Product: is to return to the current level of time, the next level will get access to the permissions of the information back to him, let him see, encourage users to do tasks or pay.
  • Me: We have a list for him to check directly, why do we need separate tips
  • Product: Are you a product or am I a product
  • Me: “Everyone is a product Manager”

Use state mode messages to remove unnecessary if else (and of course the latest requirement)

We found that if we added the permission to return to the next version, it was really enough, and after a few days there might not be any requirements, and the method seemed to crash. Looks like we need to optimize it.

First we create an abstract class (the core function is to facilitate subclass constraints and passing)

State.java

package design.pattern.Rules; import design.pattern.UserRule; import design.pattern.UserVo; import java.util.ArrayList; Public abstract class State {/** * user object */ protected UserRule UserRule; /** * protected ArrayList<String> ruleList = new ArrayList<String>() {{add()"Upload file");
            add("Download file"); }}; public State(UserRule userRule) { this.userRule = userRule; } public abstract ArrayList<String> getRuleList(UserVo userVo); }Copy the code

For the first step we need a simple parameter object (view Object in this case)

UserVo.java

package design.pattern;

public class UserVo {

    private String name;

    private Integer level;

    public UserVo(String name, Integer level) {
        this.name = name;
        this.level = level;
    }

    public String getName() {
        return name;
    }

    public Integer getLevel() {
        returnlevel; }}Copy the code

Inherit the state. Java State class to implement their respective member return classes

package design.pattern.Rules; import design.pattern.UserRule; import design.pattern.UserVo; import java.util.ArrayList; Public class MemberOne extends State {public MemberOne(UserRule UserRule) {super(UserRule); } /** * Get permission list ** @return*/ public ArrayList<String> getRuleList(UserVo UserVo) {if (userVo.getLevel() == 1) {
            return ruleList;
        } else{ userRule.setState(new MemberTwo(userRule)); // Set the next level classreturnuserRule.getRuleList(userVo); // Get details at the next level}}}Copy the code

Userrule-java (Bridge class)

package design.pattern; import design.pattern.Rules.MemberOne; import design.pattern.Rules.State; import java.util.ArrayList; Public class UserRule {/** * private State currentRule; publicUserRule() { currentRule = new MemberOne(this); } /** * set permission object ** @param state */ public voidsetState(State state) {
        this.currentRule = state;
    }


    public ArrayList<String> getRuleList(UserVo userVo) {
        returnthis.currentRule.getRuleList(userVo); }}Copy the code

The userRule class decouples a class full of conditional judgments before we optimize it. You can think of it as a bridge class that calls classes internally and exposes classes externally

The userVo object is our parameter object, which is mainly used for grade determination. If not, the next processing rule class is reset and the rule list method is also called.

The remaining two membership classes

package design.pattern.Rules; import design.pattern.UserRule; import design.pattern.UserVo; import java.util.ArrayList; Public class MemberTwo extends State {public MemberTwo(UserRule UserRule) {super(UserRule); } /** * Get permission list ** @return
     */
    public ArrayList<String> getRuleList(UserVo userVo) {

        if (userVo.getLevel() == 2) {
            ruleList.add("Speed download");
            ruleList.add("5 t space");
            return ruleList;
        }else{
            userRule.setState(new MemberThree(userRule));
            returnuserRule.getRuleList(userVo); }}}Copy the code
package design.pattern.Rules; import design.pattern.UserRule; import design.pattern.UserVo; import java.util.ArrayList; Public class MemberThree extends State {public MemberThree(UserRule UserRule) {super(UserRule); } /** * Get permission list ** @returnPublic ArrayList<String> getRuleList(UserVo UserVo) {// rulelist.add ("Speed of Light download");
        ruleList.add("10 t space");
        ruleList.add("Automatic backup of small video");
        ruleList.add("Audio and video double speed playback");
        returnruleList; }}Copy the code

For easy parameter passing management, we use a separate View Object class.

UserVo.java

package design.pattern;

public class UserVo {

    private String name;

    private Integer level;

    public UserVo(String name, Integer level) {
        this.name = name;
        this.level = level;
    }

    public String getName() {
        return name;
    }

    public Integer getLevel() {
        return level;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setLevel(int level) { this.level = level; }}Copy the code

Client call:

UserVo userVo = new UserVo("Little red", 1); UserRule userRule = new UserRule(); ArrayList<String> ruleList = userRule.getRuleList(userVo); / / print System. Out.println ("User" + userVo.getName() + "Current permissions are as follows :");
for(Object object : ruleList) { System.out.println(object); } // His next permission is uservo.setlevel (uservo.getlevel () + 1); ruleList = userRule.getRuleList(userVo); System.out.println("User" + userVo.getName() + "Will have the following permissions :");
for (Object object : ruleList) {
    System.out.println(object);
}
Copy the code

output:

User Xiaohong's current permissions are as follows: Upload file Download File user Xiaohong will have the following permissions: Upload file Download File speed download 5TB spaceCopy the code

Core code:

if (userVo.getLevel() == 1) {
    return ruleList;
} else{ userRule.setState(new MemberTwo(userRule)); // Set the next level classreturnuserRule.getRuleList(userVo); // Get details at the next level}Copy the code

Think about the problem with this code? How to optimize?

State pattern UML diagrams are the same as policy patterns

What is the difference between policy mode and state mode?

The policy pattern is very similar to the state pattern, but there are inherent differences

  • Policy patterns expose specific policy classes, and callers need to be specific about how each policy is different in order to use it correctly.
  • The change of state mode is changed by its internal conditions, and has nothing to do with the outside world. There are essential differences between them in thought.
userRule.setState(new MemberTwo(userRule));) .Copy the code

Contrast policy patterns: Detailed explanation of policy patterns

More exciting content please pay attention to the enthusiasm of small yu public account (Dull bear point pass)