设计模式-状态模式


状态模式:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类   通俗解释:改变一个状态值时,其行为发生了改变。行为也就是做了什么。   下面一个例子:(大话设计模式的例子) 一天之中的工作状态随着时间改变 早晨-精神百倍 中午-犯困 下午-状态不错 (完成工作的情况) 傍晚-下班   (没完成工作的情况) 傍晚-没完成工作-加班 晚上-困得要死   结合这个例子,编写代码

@Data
public class Work {
    private Integer hour;
    private Integer finish = 0; //默认工作没有完成

    public void writeProgram(){
        if (hour < 12){
            System.out.println("当前时间:"+hour+"点,上午工作,精神百倍");
        }else if (hour < 13){
            System.out.println("当前时间:"+hour+"点,饿了,午饭,犯困");
        }else if (hour < 17){
            System.out.println("当前时间:"+hour+"点,下午状态不错,继续努力");
        }else {
            if (finish == 1){
                System.out.println("当前时间:"+hour+"点,工作完成,下班回家");
            }else {
                if (hour < 21){
                    System.out.println("当前时间:"+hour+"点,加班,疲累至极");
                }else {
                    System.out.println("当前时间:"+hour+"点,不行了,睡着了");
                }
            }
        }
    }
}
  测试
public class WorkTest {
    public static void main(String[] args) {
        Work work = new Work();
        work.setHour(8);
        work.writeProgram();
        work.setHour(11);
        work.writeProgram();
        work.setHour(13);
        work.writeProgram();
        work.setHour(17);

        work.setFinish(1);

        work.writeProgram();
        work.setHour(18);
        work.writeProgram();
        work.setHour(20);
        work.writeProgram();
        work.setHour(22);
        work.writeProgram();
    }
}
例子中一直都是针对hour来进行判断,不同的时间点输出不同的内容 但是这样来看过多的if...else,代码过于凌乱,后期肯定不好维护 此时这种情况就可以用状态模式

State:抽象状态类,定义一个接口以封装与Context的一个特定状态的行为 ConcreteState类,具体状态的类,每个子类实现一个状态的行为 Context类,维护一个ConcreteState子类的实例,这个实例定义当前的状态  

按照UML类图来改造代码 1.创建Status类,定义每种状态下的行为

abstract class Status {
    //为什么要加一个Work的入参,需要 具体状态类来负责状态之间的转换
    //状态转换也可以放到Context类来做
    public abstract void workHandle(Work work);
}
2.创建Context类 重点是其中的Status的引用,这里我默认了status是早晨的状态

/**
 * Context类
 * @author wrj
 * @description
 * @Date 2021/12/13 2:03 下午
 */
@Data
public class Work {
    private Integer hour;
    private Integer finish = 0;
    private Status status = new MorningWorkStatus();


    public void writeProgram(){
        status.workHandle(this);
    }
}
3.创建ConcreteStatus类

/**
 * 早晨的工作状态
 * @author wrj
 * @description
 * @Date 2021/12/13 3:08 下午
 */
public class MorningWorkStatus extends Status{
    @Override
    public void workHandle(Work work) {
        if (work.getHour() < 12){
            System.out.println("当前时间:"+work.getHour()+"点,上午工作,精神百倍");
        }else {
            //条件不满足的情况下设置为中午的工作状态
            work.setStatus(new NoonWorkStatus());
            work.writeProgram();
        }
    }
}
/**
 * 中午工作状态
 * @author wrj
 * @description
 * @Date 2021/12/13 3:08 下午
 */
public class NoonWorkStatus extends Status{
    @Override
    public void workHandle(Work work) {
        if (work.getHour() < 12){
            System.out.println("当前时间:"+work.getHour()+"点,饿了,午饭,犯困");
        }else {
            //条件不满足的情况下设置为下午的工作状态
            work.setStatus(new AfterNoonWorkStatus());
            work.writeProgram();
        }
    }
}
/**
 * 下午的工作状态
 * @author wrj
 * @description
 * @Date 2021/12/13 3:08 下午
 */
public class AfterNoonWorkStatus extends Status{
    @Override
    public void workHandle(Work work) {
        if (work.getHour() <= 17){
            System.out.println("当前时间:"+work.getHour()+"点,下午状态不错,继续努力");
        }else {
            work.setStatus(new EveningWorkStatus());
            work.writeProgram();
        }
    }
}
/**
 * 傍晚的工作状态
 * @author wrj
 * @description
 * @Date 2021/12/13 3:20 下午
 */
public class EveningWorkStatus extends Status{
    @Override
    public void workHandle(Work work) {
        if (work.getFinish() == 1){
            work.setStatus(new FinishWorkStatus());
            work.writeProgram();
        }else {
            if (work.getHour() < 20){
                System.out.println("当前时间:"+work.getHour()+"点,加班,疲累至极");
            }else {
                work.setStatus(new SleepingWorkStatus());
                work.writeProgram();
            }
        }
    }
}
/**
 * 晚上快要睡着的工作状态
 * @author wrj
 * @description
 * @Date 2021/12/13 3:29 下午
 */
public class SleepingWorkStatus extends Status{
    @Override
    public void workHandle(Work work) {
        System.out.println("当前时间:"+work.getHour()+"点,不行了,睡着了");
    }
}
4.测试类

public class Test {

    public static void main(String[] args) {
        Work work = new Work();
        work.setHour(8);
        work.writeProgram();
        work.setHour(11);
        work.writeProgram();
        work.setHour(13);
        work.writeProgram();
        work.setHour(17);

        work.setFinish(0);

        work.writeProgram();
        work.setHour(18);
        work.writeProgram();
        work.setHour(20);
        work.writeProgram();
        work.setHour(22);
        work.writeProgram();
    }
}
大话设计模式中是这么说的: 将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个ConcreteState中,所以通过定义新的子类可以很容易地增加新的状态和转换   将每个状态需要做的事情封装在一个类中,不同的状态对应不同的类,对应不同的行为。当需要增加新的状态时,可以通过创建新的类来增加新的状态和行为。 上面例子中的状态转换是在具体的类中,也可以放到Context中来做,(思路:通过判断当前status的具体类型,然后赋值为下一个阶段的具体类型),然后具体的子类调用ConcreteState   使用状态模式这样做的好处是,假如公司决定晚上8点强制下班,那么只需要增加一个强制下班的子类,然后改变EveningWorkStatus的work.setStatus(new SleepingWorkStatus());将new SleepingWorkStatus()改为新创建的强制下班的子类,无须改动其他的子类。   在原有的代码上做小小的改动即可满足。但是缺点是会有很多类,容易类爆炸,推荐在状态类型不多的情况下使用状态模式