マリオでデザインパターン その1 【Strategyパターン】

StateパターンじゃなくてStrategyパターンのようなのでタイトル変更

マリオには以下のアクションがあります。

  • ジャンプ
  • パンチ

さらに以下の状態があります

それぞれの状態では以下のアクションを行います

Stateパターンを使わない例

MarioStateEnum

public enum MarioState {
	Default, Big, Fire;
}

Marioクラス

public class Mario {
	public MarioState state = MarioState.Default;

	public void jump(){
		switch(state){

		case Big:
			System.out.println("デカジャンプ");
			break;

		case Fire:
			System.out.println("ファイアジャンプ");
			break;

		case Default:
			System.out.println("デフォジャンプ");
			break;

		}
	}

	public void punch(){
		switch(state){

		case Big:
			System.out.println("デカパンチ");
			break;

		case Fire:
			System.out.println("ファイアパンチ");
			break;

		case Default:
			System.out.println("デフォパンチ");
			break;
		}
	}
}

クライアント

public class ClientMain {
	public static void main(String[] args) {
		Mario mario = new Mario();

		action(mario);
		System.out.println();

		System.out.println("--マリオはスーパーきのこを食べた-");
		mario.state = MarioState.Big;
		action(mario);
		System.out.println();


		System.out.println("--マリオはファイアフラワーを食べた-");
		mario.state = MarioState.Fire;
		action(mario);

	}

	public static void action(Mario mario){
		//ジャンプする
		System.out.println("[マリオはジャンプした]");
		mario.jump();

		//パンチする
		System.out.println("[マリオはパンチした]");
		mario.punch();
	}
}

実行結果

[マリオはジャンプした]
デフォジャンプ
[マリオはパンチした]
デフォパンチ

--マリオはスーパーきのこを食べた-
[マリオはジャンプした]
デカジャンプ
[マリオはパンチした]
デカパンチ

--マリオはファイアフラワーを食べた-
[マリオはジャンプした]
ファイアジャンプ
[マリオはパンチした]
ファイアパンチ

このパターンだと状態が増えるたびにswitch文とEnumクラスを書き直さなくてはいけません。
これをStateパターンを使うとソースを書き直さずにすみます。

Stateパターンを使った例

それぞれの状態での振る舞いの内容は違いますが、jump、puchという振る舞いは同じです。
Stateパターンは、「状態」をクラスとして表現し、振る舞いはサブクラスに任せます。


Stateパターンは、以下の構成です。

  • State

状態を表します。
状態ごとに異なる抽象化された振る舞いを定義します。

  • ConcreteState

具体的な状態を表します。
Stateインターフェース(クラス)を実装します。
抽象メソッドをオーバーライドし、具体的な振る舞いを実装します。

  • Context

状態オブジェクトを管理し、振る舞いを実行する。

【State役の作成】
State役となる状態のインターフェースを作成し、振る舞いの抽象メソッドを追加する。
ここでは、

  • jumpメソッド
  • punchメソッド

を定義します。

MarioStateインターフェース

public interface MarioState {
	public void punch();
	public void jump();
}


【ConcreteState役の作成】
ConcreteState役となる、Stateインターフェースを実装したデフォルトマリオクラスを作成する。
jump、punchメソッドをオーバーライドする
DefaultMarioStateImplクラス

public class DefaultMarioStateImpl implements MarioState {

	@Override
	public void jump() {
		System.out.println("デフォジャンプ");
	}

	@Override
	public void punch() {
		System.out.println("デフォパンチ");
	}
}

同様に、デカマリオ、ファイアマリオを作成する
DekaMarioStateImplクラス

public class DekaMarioStateImpl implements MarioState {

	@Override
	public void jump() {
		System.out.println("デカジャンプ");
	}

	@Override
	public void punch() {
		System.out.println("デカパンチ");
	}
}

FireMarioStateImplクラス

public class FireMarioStateImpl implements MarioState {

	@Override
	public void jump() {
		System.out.println("ファイアジャンプ");
	}

	@Override
	public void punch() {
		System.out.println("ファイアパンチ");
	}
}


【Context役の作成】
Context役となる、MarioStateインタフェースを含んだContextMarioクラスを作成する
MarioStateインターフェースを引数にもった

  • doJumpメソッド
  • duPunchメソッド

を実装する。
ポリモフィズムを使うことによってマリオの状態を意識する必要がなくなる。
switch文がなくなってハッピー。

public class ContextMario {
	private MarioState marioState;

	public ContextMario(){
		this.marioState = new DefaultMarioStateImpl();
	}
	public void setMarioState(MarioState marioState) {
		this.marioState = marioState;
	}

	public void doJump() {
		this.marioState.jump();
	}

	public void doPunch() {
		this.marioState.punch();
	}
}

Clientクラス

public class ClientMain {
	public static void main(String[] args) {
		ContextMario mario = new ContextMario();

		action(mario);
		System.out.println();

		System.out.println("--マリオはスーパーきのこを食べた-");
		mario.setMarioState(new DekaMarioStateImpl());
		action(mario);
		System.out.println();


		System.out.println("--マリオはファイアフラワーを食べた-");
		mario.setMarioState(new FireMarioStateImpl());
		action(mario);

	}

	public static void action(ContextMario mario){
		System.out.println("[マリオはジャンプした]");
		mario.doJump();

		System.out.println("[マリオはパンチした]");
		mario.doPunch();
	}
}

実行結果

[マリオはジャンプした]
デフォジャンプ
[マリオはパンチした]
デフォパンチ

--マリオはスーパーきのこを食べた-
[マリオはジャンプした]
デカジャンプ
[マリオはパンチした]
デカパンチ

--マリオはファイアフラワーを食べた-
[マリオはジャンプした]
ファイアジャンプ
[マリオはパンチした]
ファイアパンチ