目录
一、关于状态模式
状态模式是行为设计模式的一种,状态模式中的行为是由状态决定的,不同的状态下有不同的行为。状态模式将对象的行为封装在不同的状态对象中。
状态模式中的角色:
1)环境角色:也称为上下文,它定义了客户需要的接口,负责保持和切换状态。
2)抽象状态角色:定义一个接口,用来封装环境对象中的特定状态所对应的行为。
3)具体状态角色:实现抽象状态所对应的行为。
二、案例
用“状态模式”实现进程状态转换的程序。
操作系统中进程的五种状态,包括创建状态、就绪状态、阻塞状态、执行状态和结束状态,五种状态之间的转换以及转换条件如下图。(图片来自计算机操作系统教材)。
进程状态转换程序类图如下。
类图解析:
1)首先定义一个抽象状态角色,即状态接口AbstractState,状态接口中规定了两个方法。第一个是accept(Message msg) 方法,该方法的作用是接收信息,并且根据当前的状态和接收到的消息判断接下来切换到进程的哪一状态;第二个是stateName()方法,该方法输出当前进程所处的状态。
2)然后定义具体状态角色,实现状态接口AbstractState。分别定义五个具体状态类实现状态接口,分别为创建状态类NewState、就绪状态类ReadyState、阻塞状态类BlockedState、执行状态类RunningState以及结束状态类EndState,并且五种具体状态类均重写了接口中的两个方法。
3)定义环境角色,即CurrentState类,负责保持当前状态和状态转换。该类定义了一个状态属性,两个方法setAs(AbstractState as)和getAs()。
4)设置了一个枚举类型的消息类Message定义进程状态转换图中所有的消息。包括"MSG_EnterReadyQueue"为“进入就绪队列”消息、"MSG_IOComplete"为“I/O完成”消息、"MSG_IORequest"为“I/O请求”消息、"MSG_ProcessSchedule"为“进程调度”消息、"MSG_TimeSliceEnd"为“时间片用完”消息、"MSG_ProcessEnd"为“进程执行结束”消息。
那么是如何做到状态转换效果的呢?
是这样做到转换效果的:调用当前状态的accept(Message msg)方法,传递当前的消息。在当前状态的具体类中判断是哪个消息,根据消息判断当前要做出什么动作,即当前状态转换到什么状态,然后调用CurrentState类中的setAs(AbstractState as)方法,将目标状态对象赋予CurrentState类中的属性,即可完成状态转换。
例如,现在创建状态转换到就绪状态,需要接收消息"MSG_EnterReadyQueue",即“进入就绪队列”。NewState类代码如下。
public class NewState implements AbstractState{
@Override
public void accept(Message msg) {
if(msg == Message.MSG_EnterReadyQueue) {
System.out.println("接收消息:" + msg);
CurrentState.setAs(new ReadyState());
} else {
System.out.println("当前状态下接收的消息非法!!!");
}
}
@Override
public void stateName() {
System.out.println("现在是创建状态......");
}
}
设置当前状态为创建状态的代码如下。
AbstractState as = new NewState();
CurrentState.setAs(as);
调用NewState类中的方法,表示当前状态接收消息的代码如下。
CurrentState.getAs().accept(Message.MSG_EnterReadyQueue);
当前进程处于创建状态,此时接收消息“MSG_EnterReadyQueue” ,即“进入就绪队列”,因为CurrentState类中此时属性as = new NewState(),所以CurrentState.getAs().accept(Message.MSG_EnterReadyQueue) 调用的是具体状态类NewState中的accept(Message msg)方法,该方法判断接收到的是哪种消息,当前消息是“MSG_EnterReadyQueue”,所以执行CurrentState.setAs(new ReadyState()),转换到目标状态,即就绪状态。
以下为测试的运行结果,运行结果中包含了进程中所有状态。
测试时输入命令:
java demo3.Client "进入就绪队列" "进程调度" "进程调度" "I/O请求" "I/O完成" "进程调度" "进程执行结束"
测试结果如下。
三、附录 完整代码
package demo3;
enum Message {
MSG_EnterReadyQueue,
MSG_IOComplete,
MSG_IORequest,
MSG_ProcessSchedule,
MSG_TimeSliceEnd,
MSG_ProcessEnding
}
public interface AbstractState {
public void accept(demo3.Message msg);
public void stateName();
}
public class NewState implements AbstractState{
@Override
public void accept(Message msg) {
if(msg == Message.MSG_EnterReadyQueue) {
System.out.println("接收消息:" + msg);
CurrentState.setAs(new ReadyState());
} else {
System.out.println("当前状态下接收的消息非法!!!");
}
}
@Override
public void stateName() {
System.out.println("现在是创建状态......");
}
}
public class ReadyState implements AbstractState {
@Override
public void accept(Message msg) {
if(msg == Message.MSG_ProcessSchedule) {
System.out.println("接收消息:" + msg);
CurrentState.setAs(new RunningState());
} else {
System.out.println("当前状态下的接收消息非法!!!");
}
}
@Override
public void stateName() {
System.out.println("现在是就绪状态......");
}
}
public class BlockedState implements AbstractState{
@Override
public void accept(Message msg) {
if(msg == Message.MSG_IOComplete) {
System.out.println("接收消息:" + msg);
CurrentState.setAs(new ReadyState());
} else {
System.out.println("当前状态下接收的消息非法!!!");
}
}
@Override
public void stateName() {
System.out.println("现在是阻塞状态......");
}
}
public class RunningState implements AbstractState{
@Override
public void accept(Message msg) {
if(msg == Message.MSG_TimeSliceEnd) {
System.out.println("接收消息:" + msg);
CurrentState.setAs(new ReadyState());
} else if(msg == Message.MSG_IORequest) {
System.out.println("接收消息:" + msg);
CurrentState.setAs(new BlockedState());
} else if(msg == Message.MSG_ProcessEnding) {
System.out.println("接收消息:" + msg);
CurrentState.setAs(new EndState());
}
else {
System.out.println("当前状态下接收的消息非法!!!");
}
}
@Override
public void stateName() {
System.out.println("现在是执行状态......");
}
}
public class EndState implements AbstractState{
@Override
public void accept(Message msg) {
System.out.println("进程已经结束!!!");
}
@Override
public void stateName() {
System.out.println("现在是结束状态...");
}
}
public class CurrentState {
private static AbstractState as;
public static AbstractState getAs() {
return as;
}
public static void setAs(AbstractState as) {
CurrentState.as = as;
}
}
public class Client {
public static void main(String[] args) {
AbstractState as = new NewState();
CurrentState.setAs(as);
CurrentState.getAs().stateName();
for(String str: args) {
switch (str) {
case "进入就绪队列":
CurrentState.getAs().accept(Message.MSG_EnterReadyQueue);
CurrentState.getAs().stateName();
break;
case "进程调度":
CurrentState.getAs().accept(Message.MSG_ProcessSchedule);
CurrentState.getAs().stateName();
break;
case "时间片用完":
CurrentState.getAs().accept(Message.MSG_TimeSliceEnd);
CurrentState.getAs().stateName();
break;
case "I/O完成":
CurrentState.getAs().accept(Message.MSG_IOComplete);
CurrentState.getAs().stateName();
break;
case "I/O请求":
CurrentState.getAs().accept(Message.MSG_IORequest);
CurrentState.getAs().stateName();
break;
case "进程执行结束":
CurrentState.getAs().accept(Message.MSG_ProcessEnding);
CurrentState.getAs().stateName();
break;
default:
System.out.println("非法消息!!!");
break;
}
}
}
}