✨作者:猫十二懿
❤️账号:CSDN 、掘金 、个人博客 、Github
公众号:猫十二懿
状态模式(State)是一种行为型设计模式,当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。(可以说当到饭点了,你就会主动去找饭吃)
通常情况下,一个对象的行为会随着其内部状态的改变而发生变化,这些行为通常被包含在相应的if...else
语句中,导致代码难以维护和扩展。
适用状态模式判断状态是否改变。
状态模式的思想是将每种可能的状态都封装成一个类,因此可以在不改变原有代码的前提下动态地改变对象的行为。状态模式提供了一种简单的实现方式,即通过定义一个state接口,再定义具体的state子类,Context类中持有一个state的引用,在不同状态下,分别委托给不同的state处理相应的请求。这种实现方式将原来的大类拆分成多个小类,使得系统更加灵活、易于扩展,符合开闭原则。
状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。当然,如果这个状态判断很简单,那就没必要用状态模式了。
State类,抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为。
/**
* @author Shier
* CreateTime 2023/5/7 10:39
* 抽象状态类
*/
public abstract class State {
public abstract void handle(Context context);
}
Context类,维护一个ConcreteState子类的实例,这个实例定义当前的状态。
/**
* @author Shier
* CreateTime 2023/5/7 10:41
*
*/
public class Context {
private State state;
/**
* 初始化当前状态
* @param state
*/
public Context(State state) {
this.state = state;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
System.out.println("当前状态:"+this.state.getClass().getName());
}
/**
* 对请求做处理,并设置下一个状态
*/
public void request(){
this.state.handle(this);
}
}
ConcreteState类,具体状态,每一个子类实现一个与Context的一个状态相关的行为。
/**
* @author Shier
* CreateTime 2023/5/7 10:40
* 具体状态类A
*/
public class ConcreteStateA extends State{
/**
* 设置ConcreteStateA的下一个状态是ConcreteStateB
* @param context
*/
@Override
public void handle(Context context) {
context.setState(new ConcreteStateB());
}
}
/**
* @author Shier
* CreateTime 2023/5/7 10:45
* 具体状态类B
*/
public class ConcreteStateB extends State {
/**
* 设置ConcreteStateB的下一个状态是ConcreteStateA
* @param context
*/
@Override
public void handle(Context context) {
context.setState(new ConcreteStateA());
}
}
客户端发起请求调用
/**
* @author Shier
* CreateTime 2023/5/7 10:46
*/
public class ClientTest {
public static void main(String[] args) {
// 初始状态为ConcreteStateA
Context context = new Context(new ConcreteStateA());
// 不断请求,不断改变请求状态
context.request();
context.request();
context.request();
}
}
输出结果:
案例:不同的工作时间做不同的事情
/**
* @author Shier
* CreateTime 2023/5/7 11:01
* 工作类
*/
public class Work {
// 时间
private int hour;
// 是否完成工作任务
private boolean workFinished = false;
public int getHour() {
return hour;
}
public void setHour(int hour) {
this.hour = hour;
}
public boolean getWorkFinished() {
return workFinished;
}
public void setWorkFinished(boolean workFinished) {
this.workFinished = workFinished;
}
/**
* 工作时间段
*/
public void workTime() {
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 + "点,睡觉时间到了,躺床就睡着。");
}
}
}
}
}
客户端
/**
* @author Shier
* CreateTime 2023/5/7 11:09
*/
public class WorkClient {
public static void main(String[] args) {
Work work = new Work();
// 早上
work.setHour(9);
work.workTime();
work.setHour(11);
work.workTime();
// 中午
work.setHour(12);
work.workTime();
//下午
work.setHour(13);
work.workTime();
work.setHour(14);
work.workTime();
work.setHour(17);
//工作未完成
work.setWorkFinished(false);
// 加班
work.workTime();
work.setHour(19);
work.workTime();
work.setHour(22);
work.workTime();
}
}
结果显示:
有没有发现什么问题?workTime()这个方法已经违背了开闭原则了,每次都要修改这个方法才得以扩展新的功能
具体的结构类图
State类:
/**
* @author Shier
* CreateTime 2023/5/7 12:02
* 状态类
*/
public abstract class State {
public abstract void workTime(Work work);
}
Work工作类:
/**
* @author Shier
* CreateTime 2023/5/7 11:01
* 工作类
*/
public class Work {
/**
* 时间点
*/
private int hour;
/**
* 是否完成工作任务-是否到达下班条件
*/
private boolean workFinished = false;
/**
* 当前状态-设置下一个状态
*/
private State currentState;
/**
* 初始化状态-上午
*/
public Work() {
currentState = new ForenoonState();
}
/**
* 工作时间段-显示当前状态,并切换到下一个状态
*/
public void workTime() {
this.currentState.workTime(this);
}
public State getCurrentState() {
return currentState;
}
public void setCurrentState(State currentState) {
this.currentState = currentState;
}
public int getHour() {
return hour;
}
public void setHour(int hour) {
this.hour = hour;
}
public boolean getWorkFinished() {
return workFinished;
}
public void setWorkFinished(boolean workFinished) {
this.workFinished = workFinished;
}
}
早上具体状态:
/**
* @author Shier
* CreateTime 2023/5/7 12:02
* 早上具体状态
*/
public class ForenoonState extends State {
@Override
public void workTime(Work work) {
if (work.getHour() < 12) {
System.out.println("当前时间" + work.getHour() + "点,上午工作,精神百倍。");
} else {
// 超过12点就转入中午状态
work.setCurrentState(new NoonState());
work.workTime();
}
}
}
中午具体状态:
/**
* @author Shier
* CreateTime 2023/5/7 12:10
* 中午状态
*/
public class NoonState extends State {
@Override
public void workTime(Work work) {
if (work.getHour() < 13) {
System.out.println("当前时间" + work.getHour() + "点,饿了,午饭,犯困,午休。");
} else {
// 超过13点就转入下午工作状态
work.setCurrentState(new AfternoonState());
work.workTime();
}
}
}
下午具体状态:
/**
* @author Shier
* CreateTime 2023/5/7 12:12
* 下午具体状态
*/
public class AfternoonState extends State {
@Override
public void workTime(Work work) {
if (work.getHour() < 17) {
System.out.println("当前时间" + work.getHour() + "点,下午状态还可以,继续敲代码。");
} else {
// 超时17点就进去傍晚工作时间点
work.setCurrentState(new EveingState());
work.workTime();
}
}
}
任务完成,按时下班状态类
/**
* @author Shier
* CreateTime 2023/5/7 12:15
* 按时下班
*/
public class RestState extends State {
@Override
public void workTime(Work work) {
System.out.println("当前时间:" + work.getHour() + "点,下班回家咯!!");
}
}
工作任务未完成,加班“累”:
/**
* @author Shier
* CreateTime 2023/5/7 12:13
* 具体加班类
*/
public class EveingState extends State {
@Override
public void workTime(Work work) {
if (work.getWorkFinished()) {
// 工作完成,下班
work.setCurrentState(new RestState());
work.workTime();
} else {
// 工作没有完成则继续加班
if (work.getHour() < 21) {
System.out.println("当前时间" + work.getHour() + "点,又开始加班,疲累之极,**加班。");
} else {
// 到点睡觉
work.setCurrentState(new SleepingState());
work.workTime();
}
}
}
}
睡觉类:
/**
* @author Shier
* CreateTime 2023/5/7 12:15
* 睡觉状态
*/
public class SleepingState extends State {
@Override
public void workTime(Work work) {
System.out.println("当前时间" + work.getHour() + "点,睡觉时间到了,躺床就睡着。");
}
}
客户端同上
最终的结果也同上
虽然结果相同,但是我们的程序变得更加灵活,比如公司要求在20点之前必须离开公司, 此时我们就要新增一个“强制下班类”,并改动一下 “晚间工作状态”类的判断就可以 了。而这是不影响其他状态的代码的。实现加班类修改如下:
/**
* @author Shier
* CreateTime 2023/5/7 12:13
* 具体加班类
*/
public class EveingState extends State {
@Override
public void workTime(Work work) {
if (work.getWorkFinished()) {
// 工作完成,下班
work.setCurrentState(new RestState());
work.workTime();
} else {
// 工作没有完成则继续加班
work.setCurrentState(new ForcedLiveWork());
work.workTime();
}
}
}
强制下班类:
/**
* @author Shier
* CreateTime 2023/5/7 12:27
* 强制下班
*/
public class ForcedLiveWork extends State {
@Override
public void workTime(Work work) {
if (work.getHour() < 20) {
System.out.println("当前时间" + work.getHour() + "点,公司规定,此刻必须要离开公司了。");
} else {
// 到点睡觉
work.setCurrentState(new SleepingState());
work.workTime();
}
}
}
实现起来并不困难,只需增加一个类,再对去修改判断条件,这样就不会影响到其他状态的代码
状态模式的优点包括:
状态模式的缺点包括:
状态模式适用场景:
状态模式适用场景: