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 ());
}
}