状态模式

模式简介

允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类,(State Pattern) 是设计模式的一种,属于行为模式。

定义

(源于 Design Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。 状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。 模式中的角色

1 上下文环境(Context):它定义了客户程序需要的接口并维护一个具体状态角色的实例,将与状态相关的操作委托给当前的 Concrete State 对象来处理。

2 抽象状态(State):定义一个接口以封装使用上下文环境的的一个特定状态相关的行为。

3 具体状态(Concrete State):实现抽象状态定义的接口。

适用场景:适合于那种审批流程的,有很强的顺序性,与策略不同的是策略指导准确的类型会直接找到实现类。

状态模式的类图

状态模式

下面是一个人根据时间输出当前应该做的事情的例子,先不使用状态模式

枚举类TimeQuantum

public enum TimeQuantum {

    /**
     * 时间段一
     */
    HOUR_ONE(8),
    /**
     * 时间段二
     */
    HOUR_TWO(12),
    /**
     * 时间段三
     */
    HOUR_THREE(14),
    /**
     * 时间段四
     */
    HOUR_FOUR(18),
    /**
     * 时间段五
     */
    HOUR_FIVE(23);

    private int hour;

    TimeQuantum(int hour) {
        this.hour = hour;
    }

    public int getHour() {
        return hour;
    }

    public void setHour(int hour) {
        this.hour = hour;
    }}

Person类

@Data
@NoArgsConstructor
@AllArgsConstructor
@Slf4j
public class Person {

    private int hourOne;

    /**
     * 时间段,靠这个字段的变化来定义什么时间做什么事
     */
    private int hour;

    public void doSth() {

        if (this.hour == TimeQuantum.HOUR_ONE.getHour()) {
            log.info("现在是早上8点,上早班啦!");
        } else if (this.hour == TimeQuantum.HOUR_TWO.getHour()) {
            log.info("现在是中午12点,下班吃午饭啦!");
        } else if (this.hour == TimeQuantum.HOUR_THREE.getHour()) {
            log.info("现在是下午14点,上中班啦!");
        } else if (this.hour == TimeQuantum.HOUR_FOUR.getHour()) {
            log.info("现在是傍晚18点,下班回家啦!");
        } else if (this.hour == TimeQuantum.HOUR_FIVE.getHour()) {
            log.info("现在是晚上23点,上床睡觉啦!");
        } else if (this.hour > TimeQuantum.HOUR_FOUR.getHour() && this.hour < TimeQuantum.HOUR_FIVE.getHour()) {
            log.info("加班中...");
        } else if (this.hour > TimeQuantum.HOUR_FIVE.getHour() || this.hour < TimeQuantum.HOUR_ONE.getHour()) {
            log.info("正在睡觉...");
        } else {
            log.info("现在是上班时间!");
        }
    }
}

测试类

@Slf4j
public class StateMain {

    public static void main(String[] args) {

        Person person = new Person();

        while (true) {

            Scanner scan = new Scanner(System.in);
            System.out.println("请输入您现在的时间(24小时制整数)");
            int hour = scan.nextInt();

            person.setHour(hour);
            person.doSth();
        }
    }
}

运用状态模式

接口State

public interface State {

    /**
     * 抽象状态(接口)角色,封装了和环境类(Person类)的对象的状态(时间段的变化)相关的行为
     */
    void doSth(PersonB personB);
}

PersonB类

@Data
@Slf4j
public class PersonB {

    private int hour;

    private State state;

    public PersonB() {
        // 在构造器里初始化状态,从早晨起床开始
        this.state = new OnAnEarlyShift();
    }

    /**
     * 人(环境类)的个行为
     *
     * 状态模式允许通过改变一个对象的内部状态,来改变对象的行为,就像修改了对象的类一样!
     */
    public void doSth() {
        // 传入的是PersonB的对象
        state.doSth(this);
        // TODO 每次都从头开始搜索状态类,状态复位
        this.state = new OnAnEarlyShift();
    }
}

各种状态实现类

@Slf4j
public class OnAnEarlyShift implements State{

    public void doSth(PersonB personB) {

        if (personB.getHour() == TimeQuantum.HOUR_ONE.getHour()) {
            log.info("现在是早上8点,上早班啦!");
        } else {
            // 转移状态,明确知道要转移到哪个已有的状态!
            personB.setState(new HaveLunchAfterWork());
            // 必须要调用对应状态的行为
            personB.doSth();
        }
    }
}
@Slf4j
public class HaveLunchAfterWork implements State {

    public void doSth(PersonB personB) {
        if (personB.getHour() == TimeQuantum.HOUR_TWO.getHour()) {
            log.info("现在是中午12点,下班吃午饭啦!");
        } else {
            personB.setState(new OnTheMiddleShift());
            personB.doSth();
        }
    }

@Slf4j
public class OnTheMiddleShift implements State {

    public void doSth(PersonB personB) {
        if (personB.getHour() == TimeQuantum.HOUR_THREE.getHour()) {
            log.info("现在是下午14点,上中班啦!");
        } else {
            personB.setState(new ComeHomeFromWork());
            personB.doSth();
        }
    }

@Slf4j
public class ComeHomeFromWork implements State {

    public void doSth(PersonB personB) {
        if (personB.getHour() == TimeQuantum.HOUR_FOUR.getHour()) {
            log.info("现在是傍晚18点,下班回家啦!");
        } else {
            personB.setState(new GoToBed());
            personB.doSth();
        }
    }
}
@Slf4j
public class GoToBed implements State {

    public void doSth(PersonB personB) {
        if (personB.getHour() == TimeQuantum.HOUR_FIVE.getHour()) {
            log.info("现在是晚上23点,上床睡觉啦!");
        } else {
            personB.setState(new workOvertime());
            personB.doSth();
        }
    }
}
@Slf4j
public class workOvertime implements State {

    public void doSth(PersonB personB) {
        if (personB.getHour() > TimeQuantum.HOUR_FOUR.getHour() && personB.getHour() < TimeQuantum.HOUR_FIVE.getHour()) {
            log.info("加班中...");
        } else {
            personB.setState(new Sleeping());
            personB.doSth();
        }
    }
}
@Slf4j
public class Sleeping implements State {

    public void doSth(PersonB personB) {
        if (personB.getHour() > TimeQuantum.HOUR_FIVE.getHour() || personB.getHour() < TimeQuantum.HOUR_ONE.getHour()) {
            log.info("正在睡觉...");
        } else {
            personB.setState(new BusinessHours());
            personB.doSth();
        }
    }
}
@Slf4j
public class BusinessHours implements State {

    public void doSth(PersonB personB) {
        log.info("现在是上班时间!");
    }
}

测试类

public class StateMainB {

    public static void main(String[] args) {
        PersonB personB = new PersonB();

        while (true) {

            Scanner scan = new Scanner(System.in);
            System.out.println("请输入您现在的时间(24小时制整数)");
            int hour = scan.nextInt();

            personB.setHour(hour);
            personB.doSth();
        }

    }
}

参考资料:作者:凯睿看世界;链接:https://www.jianshu.com/p/5bf844141687