前回振り返り
State パターン
Stateパターンとは、状態がよく変わる処理を管理しやすくするデザインパターンです。状態に応じてオブジェクトの振る舞いが変わる場合に、状態を表すクラスを作成し、オブジェクトの状態を切り替えることで、条件分岐を減らすことができます。
Stateパターンには以下のような役割があります。
- State: 状態を表す抽象クラスやインタフェース。状態毎に振る舞いが異なるメソッドのインタフェースを定義する。
- ConcreteState: Stateのサブクラス。具体的な状態を表すクラスで、Stateのメソッドをオーバーライドして実装する。状態の切り替えもこのクラスが行う。
- Context: 現在の状態を保持するクラス。Stateのインスタンスを持ち、利用者からの要求をStateに委譲する。状態の変更はConcreteStateが呼び出す。
- Client: Stateパターンを利用するクラス。Contextのインスタンスを作成し、メソッドを呼び出す。
前回演習問題の解答 例
問題1
問題文
State パターン を作成してみましょう。
wikipedia のJava実装例をC#で記述してみましょう。
解答例
public interface State
{
void writeName(StateContext stateContext, String name);
}
class StateA : State
{
public void writeName(StateContext stateContext, String name)
{
Console.WriteLine(name.ToLower());
// コンテキストをStateBに遷移する
stateContext.setState(new StateB());
}
}
class StateB : State
{
private int count = 0;
public void writeName(StateContext stateContext, String name)
{
Console.WriteLine(name.ToUpper());
// StateBのwriteName()が2度呼び出された後にコンテキストをStateAに遷移する
if (++count > 1)
{
stateContext.setState(new StateA());
}
}
}
public class StateContext
{
private State myState;
public StateContext()
{
setState(new StateA());
}
// 通常は、Stateインタフェースを実装しているクラスによってのみ呼び出される
public void setState(State newState)
{
this.myState = newState;
}
public void writeName(String name)
{
this.myState.writeName(this, name);
}
}
public class TestClientState
{
public static void Main(String[] args)
{
StateContext sc = new StateContext();
sc.writeName("Monday");
sc.writeName("Tuesday");
sc.writeName("Wednesday");
sc.writeName("Thursday");
sc.writeName("Saturday");
sc.writeName("Sunday");
}
}
問題2
問題文
問1のクラスを身近なものにアレンジしてみましょう。
解答例
public interface IState
{
void action(StateContext stateContext);
}
public class StateContext
{
private IState? myState;
public StateContext()
{
setState(new SunnyState());
}
// 通常は、Stateインタフェースを実装しているクラスによってのみ呼び出される
public void setState(IState? newState)
{
this.myState = newState;
}
public bool isNotNullState()
{
return this.myState != null;
}
public void action()
{
this.myState.action(this);
}
}
class SunnyState : IState
{
private int cnt = 0;
public void action(StateContext stateContext)
{
if (++cnt > 1)
Console.Write("まだ");
Console.WriteLine("晴れているので、洗濯物を干します。");
int rndm = new Random().Next(3);
if (rndm == 0)
{
stateContext.setState(null);
}
else if (rndm == 1)
{
stateContext.setState(new RainyState());
}
else
{
// 変更なし
stateContext.setState(this);
}
}
}
class RainyState : IState
{
private int cnt = 0;
public void action(StateContext stateContext)
{
if (++cnt > 1)
{
Console.WriteLine("まだ雨が降っているので、家にいます。");
}
else
{
Console.WriteLine("雨が降ってきたので、洗濯物を取り込みます。");
}
int rndm = new Random().Next(3);
if (rndm == 0)
{
stateContext.setState(null);
}
else
{
// 変更なし
stateContext.setState(this);
}
}
}
public class TestClientState
{
public static void Main(String[] args)
{
StateContext sc = new StateContext();
while (sc.isNotNullState())
{
sc.action();
}
}
}
今回の演習問題
問題1
問題文
Factory Method パターン を作成してみましょう。
wikipedia のJava実装例をC#で記述してみましょう。
問題2
問題文
問1のクラスを身近なものにアレンジしてみましょう。
コメント