【设计模式】状态模式

发布于:2025-09-14 ⋅ 阅读:(22) ⋅ 点赞:(0)

系列文章目录



在这里插入图片描述

在上班时,都是,上午状态好,中午想睡觉,下午渐恢复,加班苦煎熬,其实这是一种状态的变化,不同的时间会有不同的状态,我们可以用代码来实现一下

工作状态 – 函数版

static int hour = 0;
    static boolean workFinished;
    public static 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(workFinished){
                System.out.println("当前时间" + hour + "下班回家");
            }else{
                if(hour < 21){
                    System.out.println("当前时间" + hour + "点,加班,疲累至极");
                }else{
                    System.out.println("当前时间" + hour + "点,不行了,睡着了");
                }
            }
        }
    }
    //主程序
    public static void main(String[] args) {
        hour = 9;
        writeProgram();
        hour = 10;
        writeProgram();
        hour = 12;
        writeProgram();
        hour = 13;
        writeProgram();
        hour = 14;
        writeProgram();
        hour = 17;
        //workFinished  // 任务完成,下班
        workFinished = false;
        writeProgram();
        hour = 19;
        writeProgram();
        hour = 22;
        writeProgram();
    }

这里代码呈现的是面向过程开发的代码,我们可以通过分几个类出来,然后通过类的属性来操作,完成上述代码任务。

工作状态 – 分类版

 class Work{
        private int hour;
        public int getHour(){
            return this.hour;
        }
        public void setHour(int value){
            this.hour = value;
        }
        private boolean workFinished = false;
        public boolean getWorkFinished(){
            return this.workFinished;
        }
        public void setWorkFinished(boolean value){
            this.workFinished = value;
        }
        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(workFinished){
                    System.out.println("当前时间" + hour + "下班回家");
                }else{
                    if(hour < 21){
                        System.out.println("当前时间" + hour + "点,加班,疲累至极");
                    }else{
                        System.out.println("当前时间" + hour + "点,不行了,睡着了");
                    }
                }
            }
        }
    }
    //客户端代码
    public static void main(String[] args) {
        Work emergencyProjects = new Work();
        emergencyProjects.setHour(9);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(10);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(12);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(13);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(14);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(17);
        emergencyProjects.setWorkFinished(false);
        //emergencyProjects.setWorkFinished(true);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(19);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(22);
        emergencyProjects.writeProgram();
    }

方法过长?

在第二版代码中,我们已经实现了所有需求,看着确实没有什么问题,在客户端代码中,“Work”类的“writeProgram(写程序)”方法过长,这里面出现了太多的判断,看起来代码并不美观,那么有什么方法来解决它呢?这个方法过长,而且有很多的判断分支,这就意味着它的责任过大了。无论是任何状态,都需要通过它来改变,这对编程来讲是很糟糕的,面向对象设计其实就是希望做到代码的责任分解。这个类违背了单一职责原则。

‘writeProgram()’ 这个方法里有太多的判断,使得任何需求的改动或者增加,都需要去更改这个方法,如果此时老板也觉得加班太久不好,影响工作效率的话,强制要求20点之前必须离开公司,面对这样的需求我们只需要更改17-22点的状态即可,但是目前的代码却是对整个方法的改动,维护出错的风险很大。所以这个writeProgram()方法,也违背了封闭–开放原则。

那么我们要如何做呢?我们可以把这些分支变成一个又一个的类,增加时不会影响其他类,然后状态的变化在各自的类完成即可,这也就是我们介绍的状态模式。

状态模式

状态模式,当一个对象的内在状态改变时允许其改变其行为,这个对象看起来像是改变了其类。

状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。 当然,如果这个状态判断很简单,那么也就没必要用‘状态模式’了。

状态模式结构图:
在这里插入图片描述
State类,抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为。

  //抽象状态类
    abstract class State{
        public abstract void handle(Context context);
    }

ConcreteState类,具体状态,每一个子类实现一个与Context的一个状态相关的行为。

 //具体状态类A
    class ConcreteStateA extends State{
        @Override
        public void handle(Context context) {
						context.setState(new ConcreteStateB());//设置ConcreteStateA的下一个状态是ConcreteStateB
        }
    }
    //具体状态类B
    class ConcreteState extends State{
        @Override
        public void handle(Context context) {
        		 context.setState(new ConcreteStateA()); //设置ConcreteStateB的下一个状态是ConcreteStateA
        }
    }

Context类,维护一个ConcreteState子类的实例,这个实例定义当前的状态

		//上下文
    class Context{
        private State state;
        public Context(State state){
            this.state = state; //初始化状态
        }
        //可读写的状态属性,用于读取当前状态和设置新状态
        public State getState(){
            return this.state;
        }
        public void setState(State value){
            this.state = value;
            System.out.println("当前状态" + this.state.getClass().getName());
        }
        public void request(){
            this.state.handle(this);
        }
    }

客户端代码:

  public static void main(String[] args) {
        Context c = new Context(new ConcreteStateA());
        c.request();
        c.request();
        c.request();
        c.request();
        c.request();//每次请求都会更改状态
    }

状态模式的好处和用处

状态模式的好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来, 就是将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个ConcreteState中,所以通过定义新的子类可以很容易的增加新的状态和转换。

这样做的目的就是为了消除庞大的条件分支语句, 大的分支判断会使得它们难以修改和扩展,任何改动和变化都是致命的,状态模式通过把各种状态转移逻辑分布到State的子类之间,来减少相互间的依赖。

当一个对象的行为取决于他的状态,并且它必须在运行时刻根据状态改变它的行为时,这时我们可以考虑使用状态模式。 另外如果业务需求某项业务有多个状态,通常都是一些枚举常量,状态的变化都是依靠大量的多分支判断语句来实现,此时应该考虑将每一种业务状态定义为一个State的子类,于是这些对象就可以不依赖于其他对象而独立变化了,如果客户需要修改需求,增加或减少业务状态或改变状态流程,都会比较方便。

工作状态 – 状态模式版

抽象状态类,定义一个抽象方法“写程序”。

abstract class State{
		public abstract void writeProgram(Work w);
}

上午和中午工作状态类:

  //上午工作状态类
    class ForenoonState extends State{
        @Override
        public void writeProgram(Work w) {
            if(w.getHour() < 12){
                System.out.println("当前钟点" + w.getHour() + "点,上午工作,精神百倍");
            }else{
                w.setState(new NoonState());
                w.writeProgram();
            }
        }
    }
      //中午工作状态类
    class NoonState extends State{
        @Override
        public void writeProgram(Work w) {
            if(w.getHour() < 13){
                System.out.println("当前时间" + w.getHour() + "点,饿了午休,犯困");
            }else {
                w.setState(new AfterNoon());
                w.writeProgram();
            }
        }
    }

下午和晚间工作状态类

//下午工作状态
public class AfterNoonState extends State{
    @Override
    public void writeProgram(Work w) {
        if(w.getHour() < 17){
            System.out.println("当前时间" + w.getHour() + "点,现在是下午工作,状态不错继续加油");
        }else{
            w.setState(new EveningState());
            w.writeProgram();
        }
    }
}
//晚间工作状态
public class EveningState extends State{
    @Override
    public void writeProgram(Work w) {
        if(w.isWorkFinished()){
            System.out.println("下班");
        }
        if(w.getHour() < 21){
            System.out.println("当前时间"  + w.getHour() + " 加班疲惫");
        }else{
            w.setState(new SleepingState());
            w.writeProgram();
        }
    }
}

睡眠状态和下班休息状态类

//睡觉状态
public class SleepingState extends State{
    @Override
    public void writeProgram(Work w) {
        System.out.println("当前时间"  + w.getHour() + "太困了顶不住了睡觉");
    }
}


//下班休息状态
public class RestState extends State{
    @Override
    public void writeProgram(Work w) {
        System.out.println("下班回家");
    }
}


工作类,此时没有了过长的分支判断语句

public class Work {
    private State current;
    public State getCurrent() {
        return current;
    }
    public void setState(State value){
        this.current = value;
    }
    public void writeProgram(){
        this.current.writeProgram(this);
    }


    private int hour;

    public int getHour() {
        return hour;
    }

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

    public boolean isWorkFinished() {
        return workFinished;
    }

    public void setWorkFinished(boolean workFinished) {
        this.workFinished = workFinished;
    }

    private boolean workFinished = false;
}

客户端代码:

//客户端代码
    public static void main(String[] args) {
        Work emergencyProjects = new Work();
        emergencyProjects.setHour(9);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(10);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(12);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(13);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(14);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(17);
        emergencyProjects.setWorkFinished(false);
        //emergencyProjects.setWorkFinished(true);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(19);
        emergencyProjects.writeProgram();
        emergencyProjects.setHour(22);
        emergencyProjects.writeProgram();
    }

这里客户端代码并没有变,但是我们的程序却更加灵活了,此时的代码,如果要完成所有员工都必须在20点之前离开公司,我们只需要增加一个强制下班状态,并改动下,晚间工作状态类的判断就可以了,这并不影响其他状态的代码!

总结

以上就是本文全部内容,本文主要向大家介绍了设计模式中的状态模式,通过对上班过程的状态转变这一现实案例,引出状态模式模板,最后将实际案例转换为状态模式代码,提高了程序的灵活性。感谢各位能够看到最后,如有问题,欢迎各位大佬在评论区指正,希望大家可以有所收获!创作不易,希望大家多多支持!