[Status Mode] Save the shit mountain code piled up by if-else

foreword

I think everyone has encountered shit mountain codes in development. These shit mountain codes are generally caused by complex and huge if-else. The state mode is a good design pattern for optimizing shit mountain codes. This article will use two examples of business scenarios to explain how to use the state pattern to save Shishan code.

Table of contents

foreword

1. Online shopping business scenario

1.1. Requirements

1.2. Implementation of if else

1.3. Realization of state mode

2. Elevator business scenario

2.1. Requirements

2.2. Implementation of if else

2.3. Realization of state mode


1. Online shopping business scenario

1.1. Requirements

Let's assume an online shopping business scenario with the following requirements:

  • The process is payment, reshipment, and receipt. The process must follow the above sequence, that is, payment cannot be made after delivery, and delivery and payment cannot be made after receipt.

  • Payment cannot be repeated after payment, delivery cannot be repeated after delivery, and delivery cannot be repeated after receipt

1.2. Implementation of if else

Here we design an Order class and use an int-type state to represent the state. Of course, it is more standardized to use an enumeration class to represent the state. This is just for convenience.

public class Order {
    //1 未付款
    //2 已付款
    //3 未发货
    //4 已发货
    //5 未收货
    //6 已收货
    private int state;
​
    public int getState() {
        return state;
    }
​
    public void setState(int state) {
        this.state = state;
    }
}

Taking the receiving method as an example, the business logic will be implemented as follows:

public void receive(Order order){
    if(order.getState()==2){
        if(order.getState()==4){
            if(order.getState()==5){
                System.out.println("收货成功");
            }else{
                System.out.println("已收货,无法重复收货");
            }
        }else{
            System.out.println("未发货");
        }
    }else{
        System.out.println("未付款");
    }
}

It can be seen that a small shit mountain code has begun to take shape, but if there are more states and more complicated business logic, this shit mountain will basically not be readable.

1.3. Realization of state mode

In fact, careful observation reveals that in many cases the state is often related to the behavior of the entity. The reason why states are introduced is that we hope that entities will exhibit different behaviors in different states.

Taking the above scenario as an example, in the payment state, we hope that the entity can show payment-related capabilities; in the delivery state, it can show delivery-related capabilities; in the receipt state, it can show the ability to receive goods.. ....

Therefore, it is completely possible to encapsulate the status and capabilities together, thereby eliminating the need for external if-else judgments. This is the so-called status mode.

The state mode can be summed up in one sentence:

Entities are in different states and have different behaviors.

The effect is:

It can save a lot of if-else logic branches brought by judgment conditions, making the code more concise and easy to read.

Next, we use the state pattern to rewrite the previous code.

First of all, let’s summarize the behaviors of the entity class. In fact, they are payment, delivery, and receipt, which are three methods. In order to standardize the code, the behavior interface can be abstracted. Of course, it is not necessary to be abstract.

public interface OrderState{
    void pay(Order order);
    void ship(Order order);
    void receive(Order order);
}

Next, summarize the status in the system. The order has six statuses in three dimensions, namely:

  • payment status

    • Unpaid

    • Already paid

  • delivery status

    • not shipped

    • Shipped

  • receipt status

    • Not received

    • received

So there are three state entities.

By binding state and behavior, the following three state entities can be obtained.

Payment status entity:

public class PayState implements OrderState{
    public void pay(Order order) {
        System.out.println("已支付,不能再次支付!");
    }
​
    public void ship(Order order) {
        order.setOrderState(new ShipState());
        System.out.println("已发货!");
    }
​
    public void receive(Order order) {
        System.out.println("未发货!不能收货!");
    }
}

Shipping Status Entity:

public class ShipState implements OrderState{
    public void pay(Order order) {
        System.out.println("已发货!禁止重复支付!");
    }
​
    public void ship(Order order) {
        System.out.println("已经发货!禁止重复支付");
    }
​
    public void receive(Order order) {
        order.setOrderState(new ReceiveState());
        System.out.println("收货成功!");
    }
}

Receipt Status Entity

public class ReceiveState implements OrderState{
    public void pay(Order order) {
        System.out.println("已收货,不能再次支付!");
    }
​
    public void ship(Order order) {
        System.out.println("已收货,不能再次发货!");
    }
​
    public void receive(Order order) {
        System.out.println("已收货,不能再次收货!");
    }
}

Test code:

public class Test {
    public static void main(String[] args) {
        Order order=new Order();
        //初始状态未待支付
        order.setOrderState(new PayState());
        order.pay();
        order.ship();
        order.receive();
    }
}

Test Results:

2. Elevator business scenario

2.1. Requirements

We consider a simple elevator system with the following states:

  1. Stopped State (StoppedState): When the elevator is in the stopped state, it can accept the request to move to the specified floor.

  2. Ascending state (MovingState): When the elevator is in the ascending state, it cannot respond to moving requests because it is ascending.

  3. Descending state (MovingState): When the elevator is in the descending state, it also cannot respond to moving requests because it is descending.

rule:

  • When the elevator is in the stopped state, it can accept the request to move to the specified floor and switch to the moving state (up or down).

  • When the elevator is in the ascending state or descending state, it cannot accept the movement request, but prompts that it is currently moving.

  • The elevator cannot respond to other movement requests during its movement until it reaches the specified floor and switches to the stop state.

In the above business scenario, we optimized the elevator system by using the state pattern. Each state (stop state and moving state) corresponds to a state class and defines the behavior in that state. The switching of the elevator state is managed by the context class (ElevatorStateContext), which is responsible for performing different behaviors in different states and switching according to the state change. By using the state pattern, we encapsulate the state switching logic into different state classes, making the code more modular and extensible.

2.2. Implementation of if else

class ElevatorIfElse {
    private String state = "停止";
    private int currentFloor = 1;
​
    public void setState(String newState) {
        state = newState;
    }
​
    public void moveToFloor(int floor) {
        if (state.equals("停止")) {
            System.out.println("电梯从 " + currentFloor + " 楼移动到 " + floor + " 楼");
            currentFloor = floor;
        } else if (state.equals("上升")) {
            System.out.println("电梯正在上升,不能移动");
        } else if (state.equals("下降")) {
            System.out.println("电梯正在下降,不能移动");
        }
    }
}
​
public class MainIfElse {
    public static void main(String[] args) {
        ElevatorIfElse elevator = new ElevatorIfElse();
​
        elevator.moveToFloor(5);
        elevator.setState("上升");
        elevator.moveToFloor(3);
        elevator.moveToFloor(7);
        elevator.setState("停止");
        elevator.moveToFloor(2);
    }
}

2.3. Realization of state mode

interface ElevatorState {
    void moveToFloor(ElevatorStateContext context, int floor);
}
​
class StoppedState implements ElevatorState {
    @Override
    public void moveToFloor(ElevatorStateContext context, int floor) {
        System.out.println("电梯从 " + context.getCurrentFloor() + " 楼移动到 " + floor + " 楼");
        context.setCurrentFloor(floor);
        context.setState(new MovingState());
    }
}
​
class MovingState implements ElevatorState {
    @Override
    public void moveToFloor(ElevatorStateContext context, int floor) {
        System.out.println("电梯正在移动,不能移动");
    }
}
​
class ElevatorStateContext {
    private ElevatorState state;
    private int currentFloor = 1;
​
    public ElevatorStateContext() {
        this.state = new StoppedState();
    }
​
    public void setState(ElevatorState state) {
        this.state = state;
    }
​
    public void moveToFloor(int floor) {
        state.moveToFloor(this, floor);
    }
​
    public int getCurrentFloor() {
        return currentFloor;
    }
​
    public void setCurrentFloor(int currentFloor) {
        this.currentFloor = currentFloor;
    }
}
​
public class MainStatePattern {
    public static void main(String[] args) {
        ElevatorStateContext context = new ElevatorStateContext();
​
        context.moveToFloor(5);
        context.setState(new MovingState());
        context.moveToFloor(3);
        context.moveToFloor(7);
        context.setState(new StoppedState());
        context.moveToFloor(2);
    }
}

Guess you like

Origin blog.csdn.net/Joker_ZJN/article/details/132281403