StateMachine
「ゆーげんじょーたいきかい」と言う奴を本質的に理解してないのでは、
無いだろうか…と言う疑問が頭にもたげたので、とりあえず実装してみた。
public abstract class Named { private String name; public Named(String n) { this.name = n; } public String getName() { return name; } @Override public int hashCode() { return name.hashCode(); } @Override public boolean equals(Object obj) { return name.equals(obj); } } public class Event extends Named { public Event(String n) { super(n); } } public class Action extends Named { public Action(String n) { super(n); } public void execute() { System.out.printf("execute:[%s] \n", getName()); } } public class Transition extends Named { private final State source, target; public Transition(State source, State target) { super(source.getName() + "_" + target.getName()); this.source = source; this.target = target; } public State getSource() { return source; } public State getTarget() { return target; } }
ここまでは簡単。単なるデータ構造だし。
で、「状態」と「状態機械」。
public class State extends Named { protected List<Action> actions = new ArrayList<Action>(); private Map<Event, Transition> transitions = new HashMap<Event, Transition>(); public State(String name) { super(name); } public void add(Action... actions) { for (Action a : actions) { this.actions.add(a); } } public void addTransition(Event event, State to) { this.transitions.put(event, new Transition(this, to)); } public State transit(Event from) { Transition t = this.transitions.get(from); State next = this; if (t != null) { next = t.getTarget(); next.executeActions(); } System.out.printf("%s => %s \n", this.getName(), next.getName()); return next; } public void executeActions() { for (Action c : this.actions) { c.execute(); } } } public class StateMachine { private State currentState; public StateMachine(State start) { this.currentState = start; } public void handle(Event event) { System.out.printf("[%s]\n", event.getName()); this.currentState = this.currentState.transit(event); } }
で、コントローラ。
public class Controller { protected Event doorClosed, drawOpened, lightOn, doorOpened, panelClosed; protected StateMachine machine; public void initialize() { Action unlockPanel = new Action("unlockPanel"); Action lockPanel = new Action("lockPanel"); Action lockDoor = new Action("lockDoor"); Action unlockDoor = new Action("unlockDoor"); this.doorClosed = new Event("doorClosed"); this.drawOpened = new Event("drawOpened"); this.lightOn = new Event("lightOn"); this.doorOpened = new Event("doorOpened"); this.panelClosed = new Event("panelClosed"); State idle = new State("idle"); State active = new State("active"); State waitingForLight = new State("waitingForLight"); State waitingForDraw = new State("waitingForDraw"); State unlockedPanel = new State("unlockedPanel"); idle.add(unlockDoor, lockPanel); idle.addTransition(this.doorClosed, active); active.addTransition(this.drawOpened, waitingForLight); active.addTransition(this.lightOn, waitingForDraw); waitingForLight.addTransition(this.lightOn, unlockedPanel); waitingForDraw.addTransition(this.drawOpened, unlockedPanel); unlockedPanel.add(unlockPanel, lockDoor); unlockedPanel.addTransition(this.panelClosed, idle); this.machine = new StateMachine(idle); } public static void main(String[] args) { Controller c = new Controller(); c.initialize(); System.out.println("ドアをとじる。"); c.machine.handle(c.doorClosed); System.out.println("電気をつける。"); c.machine.handle(c.lightOn); System.out.println("絵を開く。"); c.machine.handle(c.drawOpened); System.out.println("パネルとじる。"); c.machine.handle(c.panelClosed); } }
んぐー。
とりあえず、実装する事はでけた。
しかしだ、これが、どうなると、コンパイラになるのかワカンネ。
ANTLRの定義は、どうもStateMachineっぽく見えない事も無いんだけど、
単にそう見ようとしているから、見えるだけな気もするし。
ちなみに、この実装は、ふぁうらーたんのトコからパクってきますた。