State概述
UML概述
玩具代码案例1 - 模拟的交通信号灯
这个案例中是一个模拟的交通信号灯,它是状态的宿主,它持有一个状态对象。状态对象会自主切换宿主的状态。
状态的宿主
package online.javabook.gof.behavioral.patterns7.state1.trafficlight.context;
import online.javabook.gof.behavioral.patterns7.state1.trafficlight.state.ILightState;
public class TrafficLight {
private ILightState state;
public void setState(ILightState state) {
this.state = state;
}
public void change() {
state.change(this);
}
}
状态的接口
状态类往往会与状态的上下文关联
package online.javabook.gof.behavioral.patterns7.state1.trafficlight.state;
import online.javabook.gof.behavioral.patterns7.state1.trafficlight.context.TrafficLight;
public interface ILightState {
void change(TrafficLight light);
}
状态的实现
RedState
package online.javabook.gof.behavioral.patterns7.state1.trafficlight.state;
import online.javabook.gof.behavioral.patterns7.state1.trafficlight.context.TrafficLight;
import java.util.concurrent.TimeUnit;
public class RedState implements ILightState {
@Override
public void change(TrafficLight trafficLight) {
try {
System.out.println("现在是红灯 请等待10秒");
TimeUnit.SECONDS.sleep(10);
trafficLight.setState(new GreenState());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package online.javabook.gof.behavioral.patterns7.state1.trafficlight.state;
import online.javabook.gof.behavioral.patterns7.state1.trafficlight.context.TrafficLight;
import java.util.concurrent.TimeUnit;
public class RedState implements ILightState {
@Override
public void change(TrafficLight trafficLight) {
try {
System.out.println("现在是红灯 请等待10秒");
TimeUnit.SECONDS.sleep(10);
trafficLight.setState(new GreenState());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
GreenState
package online.javabook.gof.behavioral.patterns7.state1.trafficlight.state;
import online.javabook.gof.behavioral.patterns7.state1.trafficlight.context.TrafficLight;
import java.util.concurrent.TimeUnit;
public class GreenState implements ILightState {
@Override
public void change(TrafficLight trafficLight) {
try {
System.out.println("现在是绿灯 请等待5秒");
TimeUnit.SECONDS.sleep(5);
trafficLight.setState(new YellowState());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
YellowState
package online.javabook.gof.behavioral.patterns7.state1.trafficlight.state;
import online.javabook.gof.behavioral.patterns7.state1.trafficlight.context.TrafficLight;
import java.util.concurrent.TimeUnit;
public class YellowState implements ILightState {
@Override
public void change(TrafficLight trafficLight) {
try {
System.out.println("现在是黄灯 请等待3秒");
TimeUnit.SECONDS.sleep(3);
trafficLight.setState(new RedState());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
不基于状态模式的实现
Main
大量的if…eles语句用于状态的切换
package online.javabook.gof.behavioral.patterns7.state1.trafficlight.app.bad;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) throws InterruptedException {
String light = "Red";
while(true){
if(light.equals("Red")){
System.out.println("现在是红灯 请等待10秒");
TimeUnit.SECONDS.sleep(10);
light = "Green";
}else if(light.equals("Green")){
System.out.println("现在是绿灯 请等待5秒");
TimeUnit.SECONDS.sleep(5);
light = "Yellow";
}else if(light.equals("Yellow")){
System.out.println("现在是黄灯 请等待3秒");
TimeUnit.SECONDS.sleep(3);
light = "Red";
}
}
}
}
Console
现在是红灯 请等待10秒
现在是绿灯 请等待5秒
现在是黄灯 请等待3秒
现在是红灯 请等待10秒
现在是绿灯 请等待5秒
现在是黄灯 请等待3秒
现在是红灯 请等待10秒
......
基于状态模式的实现
Main
package online.javabook.gof.behavioral.patterns7.state1.trafficlight.app.good;
import online.javabook.gof.behavioral.patterns7.state1.trafficlight.context.TrafficLight;
import online.javabook.gof.behavioral.patterns7.state1.trafficlight.state.RedState;
public class Main {
public static void main(String[] args) {
TrafficLight trafficLight = new TrafficLight();
trafficLight.setState(new RedState());
while (true) {
trafficLight.change();
}
}
}
Console
现在是红灯 请等待10秒
现在是绿灯 请等待5秒
现在是黄灯 请等待3秒
现在是红灯 请等待10秒
现在是绿灯 请等待5秒
现在是黄灯 请等待3秒
现在是红灯 请等待10秒
......
玩具代码案例2 - 模拟iPod播放器的操作按钮
这个案例中模拟了切换播放器按钮的状态改变,例如播放状态,关机状态,暂停状态,上一首,下一首
状态上下文
package online.javabook.design.gof.behavioral7.state2.player.context;
import online.javabook.design.gof.behavioral7.state2.player.state.*;
import online.javabook.design.gof.behavioral7.state2.player.state.*;
import java.util.ArrayList;
import java.util.List;
public class IPod {
private IPodState state;
private int musicIndex = 0;
private List<String> musics = new ArrayList();
public IPod() {
musics.add("music1......");
musics.add("music2......");
musics.add("music3......");
musics.add("music4......");
musics.add("music5......");
this.setState(new On());
}
public List<String> getMusics() {
return musics;
}
public int getMusicIndex() {
return musicIndex;
}
public void setMusicIndex(int musicIndex) {
if(musicIndex<0) {
this.musicIndex = 0;
return;
}else if(musicIndex >= musics.size()) {
this.musicIndex = 0;
return;
}
this.musicIndex = musicIndex;
}
public IPodState getState() {
return state;
}
public void setState(IPodState state) {
this.state = state;
}
public void change() {
this.state.change(this);
}
public void on() {
IPodState on = new On();
on.change(this);
}
public void off() {
IPodState off = new Off();
off.change(this);
}
public void pause() {
IPodState pause = new Pause();
pause.change(this);
}
public void next() {
IPodState next = new Next();
next.change(this);
}
public void prev() {
IPodState prev = new Prev();
prev.change(this);
}
}
状态的接口
状态类往往会与状态的上下文关联
package online.javabook.gof.behavioral.patterns7.state2.player.state;
import online.javabook.gof.behavioral.patterns7.state2.player.context.IPod;
public interface IPodState {
void change(IPod pod);
}
状态的实现
On
package online.javabook.design.gof.behavioral7.state2.player.state;
import online.javabook.design.gof.behavioral7.state2.player.context.IPod;
import java.util.concurrent.TimeUnit;
public class On implements IPodState {
@Override
public void change(IPod pod) {
System.out.println("On ipod -> ");
pod.setState(this);
new Thread(() -> {
while (!(pod.getState() instanceof Off)) {
while (pod.getState() instanceof Pause) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// play music
try {
System.out.println("play " + pod.getMusics().get(pod.getMusicIndex()));
TimeUnit.SECONDS.sleep(5);
int musicIndex = pod.getMusicIndex();
pod.setMusicIndex(++musicIndex);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
Off
package online.javabook.gof.behavioral.patterns7.state2.player.state;
import online.javabook.gof.behavioral.patterns7.state2.player.context.IPod;
public class Off implements IPodState {
@Override
public void change(IPod pod) {
System.out.println("Off ipod");
pod.setState(this);
}
}
Pause
package online.javabook.design.gof.behavioral7.state2.player.state;
import online.javabook.design.gof.behavioral7.state2.player.context.IPod;
public class Pause implements IPodState {
@Override
public void change(IPod pod) {
if(pod.getState() instanceof Pause) {
pod.setState(new On());
pod.change();
} else if(pod.getState() instanceof On) {
System.out.println("Pause ipod");
pod.setState(this);
}
}
}
Next
package online.javabook.design.gof.behavioral7.state2.player.state;
import online.javabook.design.gof.behavioral7.state2.player.context.IPod;
public class Next implements IPodState {
@Override
public void change(IPod pod) {
if(!(pod.getState() instanceof Off)) {
System.out.println("On Next -> ");
int musicIndex = pod.getMusicIndex();
pod.setMusicIndex(++musicIndex);
pod.setState(this);
}
}
}
Prev
package online.javabook.design.gof.behavioral7.state2.player.state;
import online.javabook.design.gof.behavioral7.state2.player.context.IPod;
public class Prev implements IPodState {
@Override
public void change(IPod pod) {
if(!(pod.getState() instanceof Off)) {
System.out.println("On Prev -> ");
int musicIndex = pod.getMusicIndex();
pod.setMusicIndex(musicIndex-2);
pod.setState(this);
}
}
}
基于状态模式的实现
Main
package online.javabook.gof.behavioral.patterns7.state2.player.app.good;
import online.javabook.gof.behavioral.patterns7.state2.player.context.IPod;
public class Main {
public static void main(String[] args) throws InterruptedException {
IPod iPod = new IPod();
iPod.on(); // on
Thread.sleep(12000);
iPod.pause(); // on -> pause
Thread.sleep(20000);
iPod.pause(); // pause -> on
Thread.sleep(27000);
iPod.prev(); // prep
Thread.sleep(25000);
iPod.off();
}
}
Console
On ipod ->
play music1......
play music2......
play music3......
Pause ipod
On ipod ->
play music4......
play music4......
play music5......
play music1......
play music2......
play music3......
play music4......
play music5......
play music1......
play music2......
play music3......
play music4......
On Prev ->
play music3......
play music4......
play music5......
play music1......
play music2......
play music3......
play music4......
play music5......
play music1......
play music2......
Off ipod
玩具代码案例3 - 基于状态转移表的状态模式
状态模式经常与命令模式一起使用
状态上下文
流程实例
package online.javabook.gof.behavioral.patterns7.state3.workflow.context;
import online.javabook.gof.behavioral.patterns7.state3.workflow.flowstate.FlowState;
public class Flow {
private FlowState state;
public FlowState getState() {
return state;
}
public void setState(FlowState state) {
this.state = state;
}
}
环节实例
package online.javabook.gof.behavioral.patterns7.state3.workflow.context;
import online.javabook.gof.behavioral.patterns7.state3.workflow.flowstate.ActivityState;
public class Activity {
private ActivityState state;
public ActivityState getState() {
return state;
}
public void setState(ActivityState state) {
this.state = state;
}
}
状态的类型
实例状态
package online.javabook.gof.behavioral.patterns7.state3.workflow.flowstate;
public enum FlowState {
Initialize,
Running,
Canceled,
Finished,
Terminated
}
环节状态
package online.javabook.gof.behavioral.patterns7.state3.workflow.flowstate;
public enum ActivityState {
Initialize,
Committing,
Committed,
Canceled,
Approved,
Reviewing
}
命令的接口
ICommand
package online.javabook.gof.behavioral.patterns7.state3.workflow.command;
import online.javabook.gof.behavioral.patterns7.state3.workflow.context.Activity;
import online.javabook.gof.behavioral.patterns7.state3.workflow.context.Flow;
import online.javabook.gof.behavioral.patterns7.state3.workflow.statetable.FlowStateTransition;
public interface ICommand {
void doAction(Flow flow, Activity activity, FlowStateTransition workflowStateRow);
}
命令的实现
StartCommand
package online.javabook.gof.behavioral.patterns7.state3.workflow.command;
import online.javabook.gof.behavioral.patterns7.state3.workflow.context.Activity;
import online.javabook.gof.behavioral.patterns7.state3.workflow.context.Flow;
import online.javabook.gof.behavioral.patterns7.state3.workflow.statetable.FlowStateTransition;
public class StartCommand implements ICommand {
@Override
public void doAction(Flow flow, Activity activity, FlowStateTransition workflowStateRow) {
try {
System.out.println("Started");
flow.setState(workflowStateRow.getTargetFlowState());
activity.setState(workflowStateRow.getTargetActivityState());
} catch (Exception e) {
e.printStackTrace();
}
}
}
CancelCommand
package online.javabook.gof.behavioral.patterns7.state3.workflow.command;
import online.javabook.gof.behavioral.patterns7.state3.workflow.context.Activity;
import online.javabook.gof.behavioral.patterns7.state3.workflow.context.Flow;
import online.javabook.gof.behavioral.patterns7.state3.workflow.statetable.FlowStateTransition;
public class CancelCommand implements ICommand {
@Override
public void doAction(Flow flow, Activity activity, FlowStateTransition workflowStateRow) {
try {
System.out.println("Canceled");
flow.setState(workflowStateRow.getTargetFlowState());
activity.setState(workflowStateRow.getTargetActivityState());
} catch (Exception e) {
e.printStackTrace();
}
}
}
CommitCommand
package online.javabook.gof.behavioral.patterns7.state3.workflow.command;
import online.javabook.gof.behavioral.patterns7.state3.workflow.context.Activity;
import online.javabook.gof.behavioral.patterns7.state3.workflow.context.Flow;
import online.javabook.gof.behavioral.patterns7.state3.workflow.statetable.FlowStateTransition;
public class CommitCommand implements ICommand {
@Override
public void doAction(Flow flow, Activity activity, FlowStateTransition workflowStateRow) {
try {
System.out.println("Committed");
flow.setState(workflowStateRow.getTargetFlowState());
activity.setState(workflowStateRow.getTargetActivityState());
} catch (Exception e) {
e.printStackTrace();
}
}
}
RejectCommand
package online.javabook.gof.behavioral.patterns7.state3.workflow.command;
import online.javabook.gof.behavioral.patterns7.state3.workflow.context.Activity;
import online.javabook.gof.behavioral.patterns7.state3.workflow.context.Flow;
import online.javabook.gof.behavioral.patterns7.state3.workflow.statetable.FlowStateTransition;
public class RejectCommand implements ICommand {
@Override
public void doAction(Flow flow, Activity activity, FlowStateTransition workflowStateRow) {
try {
System.out.println("Rejected");
flow.setState(workflowStateRow.getTargetFlowState());
activity.setState(workflowStateRow.getTargetActivityState());
} catch (Exception e) {
e.printStackTrace();
}
}
}
FinishCommand
package online.javabook.gof.behavioral.patterns7.state3.workflow.command;
import online.javabook.gof.behavioral.patterns7.state3.workflow.context.Activity;
import online.javabook.gof.behavioral.patterns7.state3.workflow.context.Flow;
import online.javabook.gof.behavioral.patterns7.state3.workflow.statetable.FlowStateTransition;
public class FinishCommand implements ICommand {
@Override
public void doAction(Flow flow, Activity activity, FlowStateTransition workflowStateRow) {
try {
System.out.println("Finished");
flow.setState(workflowStateRow.getTargetFlowState());
activity.setState(workflowStateRow.getTargetActivityState());
} catch (Exception e) {
e.printStackTrace();
}
}
}
TerminateCommand
package online.javabook.gof.behavioral.patterns7.state3.workflow.command;
import online.javabook.gof.behavioral.patterns7.state3.workflow.context.Activity;
import online.javabook.gof.behavioral.patterns7.state3.workflow.context.Flow;
import online.javabook.gof.behavioral.patterns7.state3.workflow.statetable.FlowStateTransition;
public class TerminateCommand implements ICommand {
@Override
public void doAction(Flow flow, Activity activity, FlowStateTransition workflowStateRow) {
try {
System.out.println("Terminated");
flow.setState(workflowStateRow.getTargetFlowState());
activity.setState(workflowStateRow.getTargetActivityState());
} catch (Exception e) {
e.printStackTrace();
}
}
}
状态迁移表
FlowStateTransition
流程状态迁移,源流程状态+源环节状态 -> 目标流程状态+目标环节状态
package online.javabook.gof.behavioral.patterns7.state3.workflow.statetable;
import online.javabook.gof.behavioral.patterns7.state3.workflow.command.ICommand;
import online.javabook.gof.behavioral.patterns7.state3.workflow.flowstate.ActivityState;
import online.javabook.gof.behavioral.patterns7.state3.workflow.flowstate.FlowState;
public class FlowStateTransition {
private FlowState currentFlowState;
private ActivityState currentActivityState;
private Class<? extends ICommand> command;
private FlowState targetFlowState;
private ActivityState targetActivityState;
public FlowState getCurrentFlowState() {
return currentFlowState;
}
public void setCurrentFlowState(FlowState currentFlowState) {
this.currentFlowState = currentFlowState;
}
public ActivityState getCurrentActivityState() {
return currentActivityState;
}
public void setCurrentActivityState(ActivityState currentActivityState) {
this.currentActivityState = currentActivityState;
}
public Class<? extends ICommand> getCommand() {
return command;
}
public void setCommand(Class<? extends ICommand> command) {
this.command = command;
}
public FlowState getTargetFlowState() {
return targetFlowState;
}
public void setTargetFlowState(FlowState targetFlowState) {
this.targetFlowState = targetFlowState;
}
public ActivityState getTargetActivityState() {
return targetActivityState;
}
public void setTargetActivityState(ActivityState targetActivityState) {
this.targetActivityState = targetActivityState;
}
}
FlowStateTransitionTable
状态表用来维护所有由命令驱动的状态迁移
package online.javabook.gof.behavioral.patterns7.state3.workflow.statetable;
import online.javabook.gof.behavioral.patterns7.state3.workflow.command.ICommand;
import online.javabook.gof.behavioral.patterns7.state3.workflow.flowstate.ActivityState;
import online.javabook.gof.behavioral.patterns7.state3.workflow.flowstate.FlowState;
import java.util.ArrayList;
import java.util.List;
public class FlowStateTransitionTable {
private List<FlowStateTransition> flowStateTransitions = new ArrayList<>();
public void registerStateTransition(FlowState currentFlowState, ActivityState currentActivityState,
Class<? extends ICommand> commandClass,
FlowState targetFlowState, ActivityState targetActivityState) {
FlowStateTransition flowStateTransition = new FlowStateTransition();
flowStateTransition.setCurrentFlowState(currentFlowState);
flowStateTransition.setCurrentActivityState(currentActivityState);
flowStateTransition.setCommand(commandClass);
flowStateTransition.setTargetActivityState(targetActivityState);
flowStateTransition.setTargetFlowState(targetFlowState);
flowStateTransitions.add(flowStateTransition);
}
public FlowStateTransition getFlowStateTransition(FlowState currentFlowState, ActivityState currentActivityState, Class<? extends ICommand> commandClass) throws Exception {
for(FlowStateTransition flowStateTransition : flowStateTransitions){
if(flowStateTransition.getCurrentFlowState().equals(currentFlowState) &&
flowStateTransition.getCurrentActivityState().equals(currentActivityState) &&
flowStateTransition.getCommand().equals(commandClass)) {
return flowStateTransition;
}
}
throw new Exception("No FlowStateTransition");
}
}
基于状态的流程引擎
流程引擎往往伴随着各种命令操作和状态的改变
package online.javabook.gof.behavioral.patterns7.state3.workflow.context;
import online.javabook.gof.behavioral.patterns7.state3.workflow.command.*;
import online.javabook.gof.behavioral.patterns7.state3.workflow.flowstate.ActivityState;
import online.javabook.gof.behavioral.patterns7.state3.workflow.flowstate.FlowState;
import online.javabook.gof.behavioral.patterns7.state3.workflow.statetable.FlowStateTransition;
import online.javabook.gof.behavioral.patterns7.state3.workflow.statetable.FlowStateTransitionTable;
public class WorkflowEngine {
private FlowStateTransitionTable workflowStateTable = new FlowStateTransitionTable();
public void registerStateMachine(
FlowState currentFlowState, ActivityState currentActivityState,
Class<? extends ICommand> commandClass,
FlowState targetFlowState, ActivityState targetActivityState) {
workflowStateTable.registerStateTransition(currentFlowState, currentActivityState, commandClass, targetFlowState, targetActivityState);
}
public void StartFlow(Flow flow, Activity currentActivity) throws Exception {
FlowStateTransition flowStateTransition = workflowStateTable.getFlowStateTransition(flow.getState(), currentActivity.getState() , StartCommand.class);
ICommand command = flowStateTransition.getCommand().newInstance();
command.doAction(flow, currentActivity, flowStateTransition);
}
public void CommitFlow(Flow flow, Activity currentActivity) throws Exception {
FlowStateTransition flowStateTransition = workflowStateTable.getFlowStateTransition(flow.getState(), currentActivity.getState() , CommitCommand.class);
ICommand command = flowStateTransition.getCommand().newInstance();
command.doAction(flow, currentActivity, flowStateTransition);
}
public void CancelFlow(Flow flow, Activity currentActivity) throws Exception {
FlowStateTransition flowStateTransition = workflowStateTable.getFlowStateTransition(flow.getState(), currentActivity.getState() , CancelCommand.class);
ICommand command = flowStateTransition.getCommand().newInstance();
command.doAction(flow, currentActivity, flowStateTransition);
}
public void RejectFlow(Flow flow, Activity currentActivity) throws Exception {
FlowStateTransition flowStateTransition = workflowStateTable.getFlowStateTransition(flow.getState(), currentActivity.getState() , RejectCommand.class);
ICommand command = flowStateTransition.getCommand().newInstance();
command.doAction(flow, currentActivity, flowStateTransition);
}
public void FinishFlow(Flow flow, Activity currentActivity) throws Exception {
FlowStateTransition flowStateTransition = workflowStateTable.getFlowStateTransition(flow.getState(), currentActivity.getState() , FinishCommand.class);
ICommand command = flowStateTransition.getCommand().newInstance();
command.doAction(flow, currentActivity, flowStateTransition);
}
public void TerminateFlow(Flow flow, Activity currentActivity) throws Exception {
FlowStateTransition flowStateTransition = workflowStateTable.getFlowStateTransition(flow.getState(), currentActivity.getState() , TerminateCommand.class);
ICommand command = flowStateTransition.getCommand().newInstance();
command.doAction(flow, currentActivity, flowStateTransition);
}
}
基于状态迁移表的实现
Main
package online.javabook.gof.behavioral.patterns7.state3.workflow.app;
import online.javabook.gof.behavioral.patterns7.state3.workflow.command.*;
import online.javabook.gof.behavioral.patterns7.state3.workflow.context.Activity;
import online.javabook.gof.behavioral.patterns7.state3.workflow.context.Flow;
import online.javabook.gof.behavioral.patterns7.state3.workflow.context.WorkflowEngine;
import online.javabook.gof.behavioral.patterns7.state3.workflow.flowstate.ActivityState;
import online.javabook.gof.behavioral.patterns7.state3.workflow.flowstate.FlowState;
public class Main {
public static void main(String[] args) throws Exception {
WorkflowEngine workflowEngien = new WorkflowEngine();
workflowEngien.registerStateMachine(FlowState.Initialize, ActivityState.Initialize, StartCommand.class, FlowState.Running, ActivityState.Committing);
workflowEngien.registerStateMachine(FlowState.Running, ActivityState.Committing, CommitCommand.class, FlowState.Running, ActivityState.Committed);
workflowEngien.registerStateMachine(FlowState.Running, ActivityState.Committing, CancelCommand.class, FlowState.Canceled, ActivityState.Canceled);
workflowEngien.registerStateMachine(FlowState.Running, ActivityState.Reviewing, FinishCommand.class, FlowState.Finished, ActivityState.Approved);
workflowEngien.registerStateMachine(FlowState.Running, ActivityState.Reviewing, TerminateCommand.class, FlowState.Terminated, ActivityState.Approved);
workflowEngien.registerStateMachine(FlowState.Canceled, ActivityState.Reviewing, TerminateCommand.class, FlowState.Terminated, ActivityState.Approved);
Flow flow = new Flow();
flow.setState(FlowState.Initialize);
Activity activity = new Activity();
activity.setState(ActivityState.Initialize);
workflowEngien.StartFlow(flow, activity);
workflowEngien.CommitFlow(flow, activity);
}
}
Console
Started
Committed