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っぽく見えない事も無いんだけど、
単にそう見ようとしているから、見えるだけな気もするし。
ちなみに、この実装は、ふぁうらーたんのトコからパクってきますた。


次は、java.util.regex.Pattern読んでみるか…。