【设计模式】行为模式——状态模式

行为模式——状态模式

一、定义

状态模式是一种行为设计模式, 让你能在一个对象的内部状态变化时改变其行为, 使其看上去就像改变了自身所属的类一样。

二、问题

设置一个请假机制,比如 三天以内 导员审批。3-5 院级领导审批。5天以上学校审批。

三、解决方案

状态模式建议为对象的所有可能状态新建一个类, 然后将所有状态的对应行为抽取到这些类中。
原始对象被称为上下文 (context), 它并不会自行实现所有行为, 而是会保存一个指向表示当前状态的状态对象的引用, 且将所有与状态相关的工作委派给该对象。
如需将上下文转换为另外一种状态, 则需将当前活动的状态对象替换为另外一个代表新状态的对象。 采用这种方式是有前提的: 所有状态类都必须遵循同样的接口, 而且上下文必须仅通过接口与这些对象进行交互。

四、代码实现

1、上下文 (Context) 保存了对于一个具体状态对象的引用, 并会将所有与该状态相关的工作委派给它。 上下文通过状态接口与状态对象交互, 且会提供一个设置器用于传递新的状态对象。

package com.atmae.state;

/**
 * @Author: Mae
 * @Date: 2022/5/4
 * @Time: 13:59
 * @Description:
 */
public class AskLeave {
    
    

    private Integer day;
    private State state;

    public final Integer THREEDAT = 3;
    public final Integer FIVEDAY = 5;

    /**
     * 初始化
     *
     * @param state
     */
    public AskLeave(State state) {
    
    
        this.state = state;
    }

    public Integer getDay() {
    
    
        return day;
    }

    public void setDay(Integer day) {
    
    
        this.day = day;
    }

    public void setState(State state) {
    
    
        this.state = state;
    }

    public State getState() {
    
    
        return state;
    }

    public void request() {
    
    
        this.state.handle(this);
    }
}

2、状态 (State) 接口会声明特定于状态的方法。 这些方法应能被其他所有具体状态所理解, 因为你不希望某些状态所拥有的方法永远不会被调用。

package com.atmae.state;

/**
 * @Author: Mae
 * @Date: 2022/5/4
 * @Time: 14:00
 * @Description:
 */
public abstract class State {
    
    

    public abstract void handle(AskLeave askLeave);
}

3、具体状态 (Concrete States) 会自行实现特定于状态的方法。 为了避免多个状态中包含相似代码, 你可以提供一个封装有部分通用行为的中间抽象类。
状态对象可存储对于上下文对象的反向引用。 状态可以通过该引用从上下文处获取所需信息, 并且能触发状态转移。

上下文和具体状态都可以设置上下文的下个状态, 并可通过替换连接到上下文的状态对象来完成实际的状态转换。

package com.atmae.state;

/**
 * @Author: Mae
 * @Date: 2022/5/4
 * @Time: 14:10
 * @Description:
 */
public class CollegeState extends State {
    
    
    @Override
    public void handle(AskLeave askLeave) {
    
    
        if (askLeave.getDay()>= askLeave.THREEDAT&&askLeave.getDay()< askLeave.FIVEDAY){
    
    
            System.out.println("===学院审批===");
        }else{
    
    
            askLeave.setState(new UniversityState());
            askLeave.request();
        }
    }
}
package com.atmae.state;

/**
 * @Author: Mae
 * @Date: 2022/5/4
 * @Time: 14:10
 * @Description:
 */
public class CounselorState extends State {
    
    
    @Override
    public void handle(AskLeave askLeave) {
    
    
        if (askLeave.getDay() < askLeave.THREEDAT) {
    
    
            System.out.println("===辅导员审批===");
        } else {
    
    
            askLeave.setState(new CollegeState());
            askLeave.request();
        }
    }
}
package com.atmae.state;

/**
 * @Author: Mae
 * @Date: 2022/5/4
 * @Time: 14:11
 * @Description:
 */
public class UniversityState extends State {
    
    
    @Override
    public void handle(AskLeave askLeave) {
    
    
        System.out.println("===学校审批===");
    }
}
package com.atmae.state;

/**
 * @Author: Mae
 * @Date: 2022/5/4
 * @Time: 14:49
 * @Description:
 */
public class Client {
    
    
    public static void main(String[] args) {
    
    
        AskLeave askLeave=new AskLeave(new CounselorState());
        askLeave.setDay(6);
        askLeave.request();
    }
}

4、客户端

package com.atmae.state;

/**
 * @Author: Mae
 * @Date: 2022/5/4
 * @Time: 14:49
 * @Description:![在这里插入图片描述](https://img-blog.csdnimg.cn/6b047225bbaa4cbaa3ec899a67fda3e0.png#pic_center)

 */
public class Client {
    
    
    public static void main(String[] args) {
    
    
        AskLeave askLeave=new AskLeave(new CounselorState());
        askLeave.setDay(6);
        askLeave.request();
    }
}

五、UML图

在这里插入图片描述

六、状态模式使用场景

  • 如果对象需要根据自身当前状态进行不同行为, 同时状态的数量非常多且与状态相关的代码会频繁变更的话, 可使用状态模式。
  • 如果某个类需要根据成员变量的当前值改变自身行为, 从而需要使用大量的条件语句时, 可使用该模式。
  • 当相似状态和基于条件的状态机转换中存在许多重复代码时, 可使用状态模式。

七、总结

优点

  • 单一职责原则。 将与特定状态相关的代码放在单独的类中。
  • 开闭原则。 无需修改已有状态类和上下文就能引入新状态。
  • 通过消除臃肿的状态机条件语句简化上下文代码。

缺点

  • 如果状态机只有很少的几个状态, 或者很少发生改变, 那么应用该模式可能会显得小题大作。

八、与其他模式的关系

猜你喜欢

转载自blog.csdn.net/weixin_51799151/article/details/124569929
今日推荐