设计模式-状态模式

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

@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()改为新创建的强制下班的子类,无须改动其他的子类。
 
在原有的代码上做小小的改动即可满足。但是缺点是会有很多类,容易类爆炸,推荐在状态类型不多的情况下使用状态模式

posted @ 2021-12-14 16:10  知识海洋中的浮萍  阅读(40)  评论(0编辑  收藏  举报