Java でステート・パターン (State Pattern) を実装してみた.

よく見かける OOP のステートパターンに加えて, 手続き型パラダイム, 関数型パラダイムのステートパターンも実装した.

そもそも, ステートパターンはオブジェクト指向において,状態をカプセル化することなので, 関数型で表現することはステートパターンではない気がするが…

OOP との比較をしたいので,手続き型, 関数型ともに , class を利用して状態をあらわした.

ステートパターンの詳しい説明は以下.

オブジェクト指向パラダイム

まずは, よく見かける表現.特徴は,

  • context は 状態 (state) をもつ.
  • 状態 (state) は context への参照を保持する.
class StatePatternImperative {
	private State state;

	public StatePatternImperative () {
		this.state = new Morning ();
	}

	public void setState (State newState) {
		this.state = newState;
	}

	public void greeting () {
		state.greeting (this);
	}

	public boolean isDone () {
		return (state == null) ? true : false;
	}

	public interface State {
			public void greeting (StatePatternImperative context);
		}

	public class Morning implements State {

		public Morning () {
			System.out.println (" === It's 09:00 ===");
		}

		public void greeting (StatePatternImperative context) {
			System.out.println ("Good morning!! ('▽`)");
			context.setState (new Afternoon ());
		}
	}

	public class Afternoon implements State {

		public Afternoon () {
			System.out.println (" === It's 15:00 ===");
		}

		public void greeting (StatePatternImperative context) {
			System.out.println ("Good afternoon!! ('▽`)");
			context.setState (new Evening ());
		}
	}

	public class Evening implements State {

		public Evening () {
			System.out.println (" === It's 20:00 ===");
		}

		public void greeting (StatePatternImperative context) {
			System.out.println ("Good evening!! ('▽`)");
			context.setState (null);
		}
	}

	public static void main (String[] args) {
		StatePatternImperative context = new StatePatternImperative ();

		while (!context.isDone ()) {
			context.greeting ();
		}
	}
}

手続き型パラダイム

次は手続き型. OOP との違いは,

  • 状態を保持する context はない.
  • 次の状態は戻り値で外部に返す.
class StatePatternImperative {

	public interface State {
		public State greeting ();
	}

	public static class Morning implements State {

		public Morning () {
			System.out.println (" === It's 09:00 ===");
		}

		public State greeting () {
			System.out.println ("Good morning!! ('▽`)");
			return new Afternoon ();
		}
	}

	public static class Afternoon implements State {

		public Afternoon () {
			System.out.println (" === It's 15:00 ===");
		}

		public State greeting () {
			System.out.println ("Good afternoon!! ('▽`)");
			return new Evening ();
		}
	}

	public static class Evening implements State {

		public Evening () {
			System.out.println (" === It's 20:00 ===");
		}

		public State greeting () {
			System.out.println ("Good evening!! ('▽`)");
			return null;
		}
	}

	public static boolean isDone (State state) {
		return state == null;
	}

	public static void main (String[] args) {
		State state = new Morning ();

		while (!isDone (state)) {
			state = state.greeting ();
		}
	}
}

main () を context とみなせば, OOP とも言えなくはないが…

関数型パラダイム

最後に関数型. 手続き型との違いは,

  • 再帰的に処理する (末尾再帰)

具体的には,以下の違いかある.

        // functional paradium
	public static void run (State state) {
		if (isDone (state)) return;
		else run (state.greeting ());
	}

	public static void main (String[] args) {
		run (new Morning ());
	}

	// imperative paradium
	public static void main (String[] args) {
		State state = new Morning ();

		while (!isDone (state)) {
			state = state.greeting ();
		}
	}
class StatePatternFunctional {

	public interface State {
		public State greeting ();
	}

	public static class Morning implements State {

		public Morning () {
			System.out.println (" === It's 09:00 ===");
		}

		public State greeting () {
			System.out.println ("Good morning!! ('▽`)");
			return new Afternoon ();
		}
	}

	public static class Afternoon implements State {

		public Afternoon () {
			System.out.println (" === It's 15:00 ===");
		}

		public State greeting () {
			System.out.println ("Good afternoon!! ('▽`)");
			return new Evening ();
		}
	}

	public static class Evening implements State {

		public Evening () {
			System.out.println (" === It's 20:00 ===");
		}

		public State greeting () {
			System.out.println ("Good evening!! ('▽`)");
			return null;
		}
	}

	public static boolean isDone (State state) {
		return state == null;
	}

	public static void run (State state) {
		if (isDone (state)) return;
		else run (state.greeting ());
	}

	public static void main (String[] args) {
		run (new Morning ());
	}
}