23种设计模式之状态(State)模式

179

1、定义

允许一个对象再其内部状态改变时改变它的行为,对象看起来好像修改了它的类。通俗地说就是啊把所有行为包装在不同的类状态对象里,每一个状态对象都是抽象状态类的一个子类。

2、模式结构

状态模式由三部分组成:

  • Context(环境):定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例就是当前环境对象的现有状态。
  • State(抽象状态):定义一个接口,用以封装环境(Context)对象的一个特定的状态所对应的行为。
  • ConcreteState(具体状态):每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。

3、实例

3.1 State

public interface State {
    
    /**
     * 电审
     */
    void checkEvent(Context context);
     
     /**
      * 电商失败
      */
    void checkFailEvent(Context context);
    
    /**
     * 定价发布
     */
    void makePriceEvent(Context context);
    
    /**
     * 接单
     */
    void acceptOrderEvent(Context context);
    
    /**
     * 无人接单失效
     */
    void notPeopleAcceptEvent(Context context);
    
    /**
     * 付款
     */
    void payOrderEvent(Context context);
    
    /**
     * 有人接单支付失效
     */
    void orderFailureEvent(Context context);
     
    /**
     * 反馈
     */
    void feedBackEvent(Context context);
      
    String getCurrentState(); 
}
public enum StateEnum {
    
    GENERATE(1, "订单生成"),
    
    REVIEWED(2, "已审核"),
    
    PUBLISHED(3, "已发布"),
    
    NOT_PAY(4, "待付款"),
    
    PAID(5, "已付款"),
    
    FEED_BACKED(6, "已完结");
    
    private int key;
    
    private String value;
    
    StateEnum(int key, String value) {
        this.key = key;
        this.value = value;
    }
    
    public int getKey() {
        return key;
    }
    
    public String getValue() {
        return value;
    }
}

3.2 ConcreteState

public abstract class AbstractState implements State {
    
    protected static final RuntimeException NO_ALLOW_EXCEPTION = new RuntimeException("操作流程不允许");
    
    @Override
    public void checkEvent(Context context) {
        throw NO_ALLOW_EXCEPTION;
    }
    
    @Override
    public void checkFailEvent(Context context) {
        throw NO_ALLOW_EXCEPTION;
    }
    
    @Override
    public void makePriceEvent(Context context) {
        throw NO_ALLOW_EXCEPTION;
    }
    
    @Override
    public void acceptOrderEvent(Context context) {
        throw NO_ALLOW_EXCEPTION;
    }
    
    @Override
    public void notPeopleAcceptEvent(Context context) {
        throw NO_ALLOW_EXCEPTION;
    }
    
    @Override
    public void payOrderEvent(Context context) {
        throw NO_ALLOW_EXCEPTION;
    }
    
    @Override
    public void orderFailureEvent(Context context) { 
        throw NO_ALLOW_EXCEPTION;
    }
    
    @Override
    public void feedBackEvent(Context context) {
        throw NO_ALLOW_EXCEPTION;
    }
    
    @Override
    public String getCurrentState() {
        throw NO_ALLOW_EXCEPTION;
    }
}
public class GenerateState extends AbstractState {
    
    @Override
    public void checkEvent(Context context) {
        context.setState(new ReviewState());
    }
    
    @Override
    public void checkFailEvent(Context context) {
        context.setState(new FeedBackState());
    }
    
    @Override
    public String getCurrentState() {
        return StateEnum.GENERATE.getValue();
    }
}
public class ReviewState extends AbstractState {
    
    @Override
    public void makePriceEvent(Context context) {
        context.setState(new PublishState());
    }
    
    @Override
    public String getCurrentState() {
        return StateEnum.REVIEWED.getValue();
    }
}
public class PublishState extends AbstractState {
    
    @Override
    public void acceptOrderEvent(Context context) {
        context.setState(new NotPayState());
    }
    
    @Override
    public void notPeopleAcceptEvent(Context context) {
        context.setState(new FeedBackState());
    }
    
    @Override
    public String getCurrentState() {
        return StateEnum.PUBLISHED.getValue();
    }
}
public class NotPayState extends AbstractState {

    @Override
    public void payOrderEvent(Context context) {
        context.setState(new PaidState());
    }
    
    @Override
    public void feedBackEvent(Context context) {
        context.setState(new FeedBackState());
    }
    
    @Override
    public String getCurrentState() {
        return StateEnum.NOT_PAY.getValue();
    }
}
public class PaidState extends AbstractState {
    
    @Override
    public void feedBackEvent(Context context) {
        context.setState(new FeedBackState());
    }
    
    @Override
    public String getCurrentState() {
        return StateEnum.PAID.getValue();
    }
}
public class FeedBackState extends AbstractState {
    
    @Override
    public String getCurrentState() {
        return StateEnum.FEED_BACKED.getValue();
    }
}

3.3 Context

public class Context implements State {
    
    private State state;
    
    @Override
    public void checkEvent(Context context) {
        state.checkEvent(this);
        getCurrentState();
    }
    
    @Override
    public void checkFailEvent(Context context) {
        state.checkFailEvent(this);
        getCurrentState();
    }
    
    @Override
    public void makePriceEvent(Context context) {
        state.makePriceEvent(this);
        getCurrentState();
    }
    
    @Override
    public void acceptOrderEvent(Context context) {
        state.acceptOrderEvent(this);
        getCurrentState();
    }
    
    @Override
    public void notPeopleAcceptEvent(Context context) {
        state.notPeopleAcceptEvent(this);
        getCurrentState();
    }
    
    @Override
    public void payOrderEvent(Context context) {
        state.payOrderEvent(this);
        getCurrentState();
    }
    
    @Override
    public void orderFailureEvent(Context context) {
        state.orderFailureEvent(this);
        getCurrentState();
    }
    
    @Override
    public void feedBackEvent(Context context) {
        state.feedBackEvent(this);
        getCurrentState();
    }
    
    @Override
    public String getCurrentState() {
        System.out.println("当前状态:" + state.getCurrentState());
        return state.getCurrentState();
    }
    
    public State getState() {
        return state;
    }
    
    public void setState(State state) { 
        this.state = state;
    }
}

3.4 客户端调用

public class Client {
    
    public static void main(String[] args) {
        
        Context context = new Context();
        context.setState(new PublishState());
        
        context.acceptOrderEvent(context);
        
        context.payOrderEvent(context);

        try {
            context.checkFailEvent(context);
            System.out.println("流程正常。。。");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

4、适用场景

  • 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态来改变它的行为。
  • 一个操作中包含大量分支的条件语句,且这些分支依赖于该对象的状态,同时状态分支还有可能继续增加。

5、优缺点

5.1 优点
  • 封装了状态的转换规则,在状态模式中可以将状态的转换代码封装在环境类或者具体状态类中,可以对状态转换代码进行集中管理,而不是分散在一个个业务方法中。
  • 将所有与某个状态有关的行为放到一个类中,只需要注入一个不同的状态对象即可使环境对象拥有不同的行为。
  • 允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块,状态模式可以让我们避免使用庞大的条件语句来将业务方法和状态转换代码交织在一起。
  • 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
5.2 缺点
  • 状态模式的使用必然会增加系统中类和对象的个数,导致系统运行开销增大。
  • 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱,增加系统设计的难度。
  • 状态模式对“开闭原则”的支持并不太好,增加新的状态类增加修改那些负责状态转换的源代码,否则无法转换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

源代码:github.com/freedom9/de…