说明
状态模式(State):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
UML
角色:
State:抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为。
ConcreteState:具体状态类,每一个子类实现一个与Context的一个状态相关的行为。
Context:维护一个状态对象的实例,这个实例定义当前状态。
代码
以一天的工作状态来举例,不同时段有不同的工作状态。
-
9-12 上午
-
12-13 中午
-
13-18 下午
-
完成工作后 18点以后是休息状态
-
未完成工作
- 18-21加班
- 超过21睡着
此例取自《大话设计模式》,代码如下。
抽象状态
/**
* 抽象状态
*
* @author ctl
* @date 2021/1/29
*/
public interface State {
void writeProgram(Work work);
}
具体状态,上午工作状态
/**
* 上午工作状态
*
* @author ctl
* @date 2021/1/29
*/
public class ForenoonState implements State {
@Override
public void writeProgram(Work work) {
if (work.getHour() < 12) {
System.out.println("当前时间:" + work.getHour() + "点,上午工作,精神百倍");
} else {
// 超过12点转入中午工作状态
work.setCurrent(new NoonState());
work.writeProgram();
}
}
}
具体状态,中午状态
/**
* 中午状态
*
* @author ctl
* @date 2021/1/29
*/
public class NoonState implements State {
@Override
public void writeProgram(Work work) {
if (work.getHour() < 13) {
System.out.println("当前时间:" + work.getHour() + "点,饿了吃饭,犯困午休");
} else {
// 超过13点转入下午工作状态
work.setCurrent(new AfternoonState());
work.writeProgram();
}
}
}
具体状态,下午工作状态
/**
* 下午工作状态
*
* @author ctl
* @date 2021/1/29
*/
public class AfternoonState implements State {
@Override
public void writeProgram(Work work) {
if (work.getHour() < 18) {
System.out.println("当前时间:" + work.getHour() + "点,下午状态还不错,继续努力");
} else {
// 超过18点转入晚间工作状态
work.setCurrent(new EveningState());
work.writeProgram();
}
}
}
具体状态,晚间工作状态
/**
* 晚间工作状态
*
* @author ctl
* @date 2021/1/29
*/
public class EveningState implements State {
@Override
public void writeProgram(Work work) {
if (work.isFinish()) {
// 工作完成 下班
work.setCurrent(new RestState());
work.writeProgram();
} else {
if (work.getHour() < 21) {
System.out.println("当前时间:" + work.getHour() + "点,持续搬砖有点累");
} else {
// 超过21点 转入睡眠状态
work.setCurrent(new SleepState());
work.writeProgram();
}
}
}
}
具体状态,下班状态
/**
* 休息状态
*
* @author ctl
* @date 2021/1/29
*/
public class RestState implements State {
@Override
public void writeProgram(Work work) {
System.out.println("当前时间:" + work.getHour() + "点,下班回家了");
}
}
具体状态,睡眠状态
/**
* 睡眠状态
*
* @author ctl
* @date 2021/1/29
*/
public class SleepState implements State {
@Override
public void writeProgram(Work work) {
System.out.println("当前时间:" + work.getHour() + "点,不行了,睡着了");
}
}
Context角色,工作类
/**
* 工作,Context角色
*
* @author ctl
* @date 2021/1/29
*/
public class Work {
private State current;
// 时间
private int hour;
// 工作是否完成,能否下班的依据
private boolean finish;
public Work() {
// 初始化为上午工作状态,即9点开始上班
this.current = new ForenoonState();
}
public void writeProgram(){
current.writeProgram(this);
}
public void setCurrent(State current) {
this.current = current;
}
public int getHour() {
return hour;
}
public void setHour(int hour) {
this.hour = hour;
}
public boolean isFinish() {
return finish;
}
public void setFinish(boolean finish) {
this.finish = finish;
}
}
测试类
/**
* @author ctl
* @date 2021/1/29
*/
public class StateMain {
public static void main(String[] args) {
System.out.println("---------一天的工作状态---------");
Work work = new Work();
work.setHour(9);
work.writeProgram();
work.setHour(10);
work.writeProgram();
work.setHour(12);
work.writeProgram();
work.setHour(13);
work.writeProgram();
work.setHour(14);
work.writeProgram();
work.setHour(18);
work.writeProgram();
System.out.println("---------工作按时完成后的晚间状态---------");
work.setFinish(true);
work.setHour(20);
work.writeProgram();
work.setHour(24);
work.writeProgram();
System.out.println("---------工作未按时完成的晚间状态---------");
Work work2 = new Work();
work2.setFinish(false);
work2.setHour(20);
work2.writeProgram();
work2.setHour(24);
work2.writeProgram();
}
}
结果
总结
状态模式的好处就是将与特定状态的行为局部化,并且将不同的状态行为分割开。
说白了就是将特定状态的行为都封装到一个对象中,由于所有与状态相关的代码都存在于某一个ConcreteState中,所以通过定义新的子类可以很容易地增加新的状态和转换。这样做的目的就是为了去除庞大的条件分支语句,也就是if else或seitch case。
状态模式也是通过把各种状态间的转移逻辑分布到State的子类间,来减少相互间的依赖。
当一个对象的行为取决于它的状态,并且它必须根据运行时刻的状态来判断要做出哪种行为时,就可以考虑状态模式了。
思考:
从实现方式上,uml类图上,还有功能上,是不是和策略模式都有点像?
其实二者确实有相似之处,但侧重点与出发点不同,切记不要搞混,区别如下:
1、状态模式重点在各状态之间的切换,从而做不同的事情;而策略模式更侧重于根据具体情况选择策略,并不涉及切换。
2、状态模式不同状态下做的事情不同,而策略模式做的都是同一件事。
3、状态模式中状态的切换是无意识的,客户端无需考虑的,而策略模式是要客户端明确要使用的策略。策略是外界给的,是调用者考虑的事情,状态是根据入参自动切换的。