おーみんブログ

C#, ASP.NET Core, Unityが大好きです。

C#でStateパターンを体験してみた。

はじめに

GoFデザインパターンの1つであるStateパターンを体験してみました。

Stateパターンとは

Stateパターンとは「状態」をクラスとして持ち、その変化を管理しやすくするためのデザインパターンです。 「状態」を表すStateインターフェースを継承して具体的な「状態」を持つクラスを作成、そしてその「状態」をContextクラスで管理する、というイメージです。なかなか説明が難しくて申し訳ないのですがWikipediaから引用したクラス図を以下に添付いたします。

ja.wikipedia.org

サンプルコード

以下にサンプルコードを記載します。 Contextクラスで状態を管理して(セットして)、その状態に応じた処理が動いていることが分かります。

public class Program
{
    static void Main(string[] args)
    {
        var context = new Context();
        var dayOfWeekList = new List<string>() { "Monday", "Sunday" };
        foreach(var dayOfWeek in dayOfWeekList)
        {
            Console.WriteLine($"---- {dayOfWeek} ----");
            context.SetState(dayOfWeek);
            context.GetMorning();
            context.GetAfternoon();
        }
    }
}

public interface IState
{
    void Morning();
    void Afternoon();
}

// 平日の具体的な状態を作成します。
public class Weekday : IState
{
    public void Morning() => Console.WriteLine("朝:早起きをします。");
    public void Afternoon() => Console.WriteLine("昼:仕事を一生懸命します。");
}

// 休日の具体的な状態を作成します。
public class Holiday : IState
{
    public void Morning() => Console.WriteLine("朝:寝ます。");
    public void Afternoon() => Console.WriteLine("昼:寝ます。");
}

// 状態を管理するクラスです。
public class Context
{
    private IState _state;

    public void SetState(string dayOfWeek)
    {
        switch (dayOfWeek)
        {
            case "Saturday" or "Sunday":
                _state = new Holiday();
                break;
            default:
                _state = new Weekday();
                break;
        }
    }
    public void GetMorning() => _state.Morning();
    public void GetAfternoon() => _state.Afternoon();
}
---- Monday ----
朝:早起きをします。
昼:仕事を一生懸命します。
---- Sunday ----
朝:寝ます。
昼:寝ます。

今回はなるべく少ない量にしたかったので上記のようなコードにしていますが、調べた感じですと具体的な状態を記載しているクラス(上記だとWeekdayクラスやHolidayクラス)の生成はSingletonパターンを利用しているものも見られましたので1状態につき複数のインスタンスを生成する必要がない場合はそのように実装するのも良いと思います。

おわりに

実はStateパターンを知らずにif文で全部対処したことがありまして... 新しい状態が加わってかつその中の振る舞いも追加されてif文が鬼ネストしたことを思い出しました。あの時これを知っていればもう少し良くなっていたのかな...とも思うと同時に勉強不足を反省しました( ;∀;) もっとしっかり理解してより良いコードが書けるように頑張るぞーー!!

参考にさせていただいたサイト

今回の記事を書くにあたり、以下の記事を参考にさせていただきました。とても勉強になりました!ありがとうございました!!

qiita.com

www.techscore.com

www.itsenka.com

tech-blog.cloud-config.jp