An Embedded Engineer’s Blog

とある組み込みエンジニアの備忘録的なブログです。

UMLのステートマシン図を実装する for C# - その4

まえがき

今回は、前回に引き続きサンプルのエアコンステートマシンを実装していきます。

f:id:an-embedded-engineer:20190414174321p:plain
エアコンステートマシン


State クラス

State クラスを継承した各状態を実装します。
エアコンステートマシンでは、4 つのメイン状態と、6つのサブ状態を実装する必要があります。

ステートマシン 名称 詳細 備考
ModelStateMachine InitialState 初期状態
ModelStateMachine StopState 停止状態
ModelStateMachine RunningState 動作状態
ModelStateMachine CleanState クリーニング状態
RunningStateMachine CoolState 冷房制御状態
RunningStateMachine HeatState 暖房制御状態
RunningStateMachine DryState 除湿制御状態
CleanStateMachine StainLvelAnalysisState 汚れレベル解析状態
CleanStateMachine DeepCleanState 入念クリーニング状態
CleanStateMachine LightCleanState あっさりクリーニング状態
CleanStateMachine CleanFinalState クリーニング完了状態


各状態はシステム内で 1 つのインスタンスのみを持つべきなので、シングルトンで実装します。


InitialState クラス

InitialState クラスでは、Entry イベントハンドラでモデル(AirConditioner)の初期化処理を行います。
初期化完了後、Initialize トリガをステートマシンに送信します。

private void EntryEventHandler(StateMachine context)
{
    // StateMachineをダウンキャスト
    var stm = context.GetAs<ModelStateMachine>();

    // モデル(AirConditionerクラス)を取得
    var model = stm.Model;

    // モデルの初期化処理
    model.Initialize();

    // Initialiedトリガ送信
    stm.SendTrigger(InitializedTrigger.Instance);
}


また、トリガアクションハッシュテーブルに、Initialized トリガに対するアクション(InitializedTriggerHandler)を登録しておきます。

protected override TriggerActionMap GenerateTriggerActionMap()
{
    return new TriggerActionMap()
    {
        // Initializedトリガに対するアクションの登録
        { InitializedTrigger.Instance.Name, this.InitializedTriggerHandler },
    };
}


InitializedTriggerHandler では、コンテキスト(ステートマシン)に対して Stop 状態への状態遷移を要求します。

private void InitializedTriggerHandler(TriggerActionArgs args)
{
    // コンテキスト(ステートマシン)の取得
    var context = args.Context;

    // Stop状態への状態遷移を要求
    context.ChangeState(StopState.Instance);
}


ソース全体を示します。

public sealed class InitialState : State
{
    // シングルトンインスタンス
    public static InitialState Instance { get; private set; } = new InitialState();

    // コンストラクタ
    private InitialState() : base("Initial")
    {
        this.OnEntry += this.EntryEventHandler;
    }

    // トリガアクションハッシュテーブル生成
    protected override TriggerActionMap GenerateTriggerActionMap()
    {
        return new TriggerActionMap()
        {
            { InitializedTrigger.Instance.Name, this.InitializedTriggerHandler },
        };
    }

    // Entryイベントハンドラ
    private void EntryEventHandler(StateMachine context)
    {
        var stm = context.GetAs<ModelStateMachine>();

        var model = stm.Model;

        model.Initialize();

        stm.SendTrigger(InitializedTrigger.Instance);
    }

    // Initializedトリガハンドラ
    private void InitializedTriggerHandler(TriggerActionArgs args)
    {
        var context = args.Context;

        context.ChangeState(StopState.Instance);
    }
}


StopState クラス

StopState クラスでは、SwitchStart トリガに対して、RunningState への状態遷移を要求する処理を実装します。

protected override TriggerActionMap GenerateTriggerActionMap()
{
    return new TriggerActionMap()
    {
        // SwitchStartトリガに対するアクション
        { SwitchStartTrigger.Instance.Name, this.SwitchStartTriggerHandler },
    };
}

private void SwitchStartTriggerHandler(TriggerActionArgs args)
{
    // コンテキスト(ステートマシン)の取得
    var context = args.Context;

    // Running状態への状態遷移を要求
    context.ChangeState(RunningState.Instance);
}


ソース全体を示します。

public sealed class StopState : State
{
    // シングルトンインスタンス
    public static StopState Instance { get; private set; } = new StopState();

    // コンストラクタ
    private StopState() : base("Stop")
    {
    }

    // トリガアクションハッシュテーブル生成
    protected override TriggerActionMap GenerateTriggerActionMap()
    {
        return new TriggerActionMap()
        {
            { SwitchStartTrigger.Instance.Name, this.SwitchStartTriggerHandler },
        };
    }

    // SwitchStartトリガハンドラ
    private void SwitchStartTriggerHandler(TriggerActionArgs args)
    {
        var context = args.Context;

        context.ChangeState(RunningState.Instance);
    }
}


RunningState クラス

RunningState クラスでは、サブステートマシンとして RunningStateMachine を持つ必要があります。

// サブステートマシン
public RunningStateMachine SubContext { get; private set; }


RunningStateMachine は、最初に Running 状態に入った(Entry イベント)時のみインスタンスが生成されます。
Hisoty 疑似状態を実現するために、Running 状態を出た際に最後のサブ状態を記憶しておく必要があるためです。

private void EntryEventHandler(StateMachine context)
{
    // 初回入場時(サブステートマシンのインスタンスが生成されていない)
    if (this.SubContext == null)
    {
        // 親ステートマシン(ModelStateMachine)の取得
        var parent = context.GetAs<ModelStateMachine>();

        // サブステートマシン(RunningStateMachine)のインスタンスを生成
        this.SubContext = new RunningStateMachine(parent);
    }
}


また、サブステートマシンの定常的な処理を実行するため、Do イベントハンドラで、サブステートマシンの Update 処理を実行します。

private void DoEventHandler(StateMachine context)
{
    // サブステートマシンの更新
    this.SubContext.Update();
}


RunningStete クラスでは、Running 状態そのものに対するトリガと、サブ状態に対するトリガを受け取れるようにする必要があります。

protected override TriggerActionMap GenerateTriggerActionMap()
{
    return new TriggerActionMap()
    {
        // SwitchStopトリガに対するアクション
        { SwitchStopTrigger.Instance.Name, this.SwitchStopTriggerHandler },
        // SwitchCleanトリガに対するアクション
        { SwitchCleanTrigger.Instance.Name, this.SwitchCleanTriggerHandler },
        // SwitchCoolトリガに対するアクション
        { SwitchCoolTrigger.Instance.Name, this.SubContextTriggerHandler },
        // SwitchHeatトリガに対するアクション
        { SwitchHeatTrigger.Instance.Name, this.SubContextTriggerHandler },
        // SwitchDryトリガに対するアクション
        { SwitchDryTrigger.Instance.Name, this.SubContextTriggerHandler },
    };
}


SwitchStop トリガを受信した場合は、Stop 状態への遷移を要求し、その際に Trigger に設定された Effect をパラメータとして受け渡します。
SwitchClean トリガを受信した場合は、Clean 状態への遷移を要求します。

private void SwitchStopTriggerHandler(TriggerActionArgs args)
{
    // コンテキスト(ステートマシン)の取得
    var context = args.Context;

    // 状態遷移時に実行するEffectを取得
    var effect = args.Trigger.Effect;

    // Stop状態への状態遷移を要求
    context.ChangeState(StopState.Instance, effect);
}

private void SwitchCleanTriggerHandler(TriggerActionArgs args)
{
    // コンテキスト(ステートマシン)の取得
    var context = args.Context;

    // Clean状態への状態遷移を要求
    context.ChangeState(CleanState.Instance);
}


サブステートマシン用のトリガ(SwitchCool / SwitchHeat / SwitchDry)を受信した場合は、サブステートマシンに受信したトリガを送信します。

private void SubContextTriggerHandler(TriggerActionArgs args)
{
    // 受信したトリガを取得
    var trigger = args.Trigger;

    // コンテキスト(サブステートマシン)を取得
    var context = this.SubContext;

    // サブステートマシンにトリガを送信
    context.SendTrigger(trigger);
}


ソース全体を示します。

public sealed class RunningState : State
{
    // シングルトンインスタンス
    public static RunningState Instance { get; private set; } = new RunningState();

    // サブステートマシン
    public RunningStateMachine SubContext { get; private set; }

    // コンストラクタ
    private RunningState() : base("Running")
    {
        this.OnEntry += this.EntryEventHandler;
        this.OnDo += this.DoEventHandler;
    }

    // トリガアクションハッシュテーブル生成
    protected override TriggerActionMap GenerateTriggerActionMap()
    {
        return new TriggerActionMap()
        {
            { SwitchStopTrigger.Instance.Name, this.SwitchStopTriggerHandler },
            { SwitchCleanTrigger.Instance.Name, this.SwitchCleanTriggerHandler },
            { SwitchCoolTrigger.Instance.Name, this.SubContextTriggerHandler },
            { SwitchHeatTrigger.Instance.Name, this.SubContextTriggerHandler },
            { SwitchDryTrigger.Instance.Name, this.SubContextTriggerHandler },
        };
    }

    // Entryイベントハンドラ
    private void EntryEventHandler(StateMachine context)
    {
        if (this.SubContext == null)
        {
            var parent = context.GetAs<ModelStateMachine>();

            this.SubContext = new RunningStateMachine(parent);
        }
    }

    // Doイベントハンドラ
    private void DoEventHandler(StateMachine context)
    {
        this.SubContext.Update();
    }

    // SwitchStopトリガハンドラ
    private void SwitchStopTriggerHandler(TriggerActionArgs args)
    {
        var context = args.Context;

        var effect = args.Trigger.Effect;

        context.ChangeState(StopState.Instance, effect);
    }

    // SwitchCleanトリガハンドラ
    private void SwitchCleanTriggerHandler(TriggerActionArgs args)
    {
        var context = args.Context;

        context.ChangeState(CleanState.Instance);
    }

    // サブステートマシン用トリガハンドラ
    private void SubContextTriggerHandler(TriggerActionArgs args)
    {
        var trigger = args.Trigger;

        var context = this.SubContext;

        context.SendTrigger(trigger);
    }
}


CoolState クラス

CoolState クラスでは、Do イベントハンドラで冷房制御を行うため、モデル(AirConditioner)の冷房制御処理(CoolControl)を呼び出します。

private void DoEventHandler(StateMachine context)
{
    // 親ステートマシン(RunningStateMachine)の取得
    var stm = context.GetAs<RunningStateMachine>();

    // モデル(AirConditioner)の取得
    var model = stm.Model;

    // 冷房制御処理呼び出し
    model.CoolControl();
}


CoolState クラスでは、動作モード(暖房 / 除湿)切り替えスイッチ押下によるトリガを受信できるようにしておきます。

protected override TriggerActionMap GenerateTriggerActionMap()
{
    return new TriggerActionMap()
    {
        // SwitchHeatトリガに対するアクション
        { SwitchHeatTrigger.Instance.Name, this.SwitchHeatTriggerHandler },
        // SwitchDryトリガに対するアクション
        { SwitchDryTrigger.Instance.Name, this.SwitchDryTriggerHandler },
    };
}


SwitchHeat トリガを受信した場合は、Heat 状態への遷移を要求します。
SwitchDry トリガを受信した場合は、Dry 状態への遷移を要求します。

private void SwitchHeatTriggerHandler(TriggerActionArgs args)
{
    // コンテキスト(ステートマシン)の取得
    var context = args.Context;

    // Heat状態への状態遷移を要求
    context.ChangeState(HeatState.Instance);
}

private void SwitchDryTriggerHandler(TriggerActionArgs args)
{
    // コンテキスト(ステートマシン)の取得
    var context = args.Context;

    // Dry状態への状態遷移を要求
    context.ChangeState(DryState.Instance);
}


ソース全体を示します。

public sealed class CoolState : State
{
    // シングルトンインスタンス
    public static CoolState Instance { get; private set; } = new CoolState();

    // コンストラクタ
    private CoolState() : base("Cool")
    {
        this.OnDo += this.DoEventHandler;
    }

    // トリガアクションハッシュテーブル生成
    protected override TriggerActionMap GenerateTriggerActionMap()
    {
        return new TriggerActionMap()
        {
            { SwitchHeatTrigger.Instance.Name, this.SwitchHeatTriggerHandler },
            { SwitchDryTrigger.Instance.Name, this.SwitchDryTriggerHandler },
        };
    }

    // Doイベントハンドラ
    private void DoEventHandler(StateMachine context)
    {
        var stm = context.GetAs<RunningStateMachine>();

        var model = stm.Model;

        model.CoolControl();
    }

    // SwitchHeatトリガハンドラ
    private void SwitchHeatTriggerHandler(TriggerActionArgs args)
    {
        var context = args.Context;

        context.ChangeState(HeatState.Instance);
    }

    // SwitchDryトリガハンドラ
    private void SwitchDryTriggerHandler(TriggerActionArgs args)
    {
        var context = args.Context;

        context.ChangeState(DryState.Instance);
    }
}


HeatState クラス

HeatState クラスでは、Do イベントハンドラで暖房制御を行うため、モデル(AirConditioner)の暖房制御処理(HeatControl)を呼び出します。

private void DoEventHandler(StateMachine context)
{
    // 親ステートマシン(RunningStateMachine)の取得
    var stm = context.GetAs<RunningStateMachine>();

    // モデル(AirConditioner)の取得
    var model = stm.Model;

    // 暖房制御処理呼び出し
    model.HeatControl();
}


HeatState クラスでは、動作モード(冷房 / 除湿)切り替えスイッチ押下によるトリガを受信できるようにしておきます。

protected override TriggerActionMap GenerateTriggerActionMap()
{
    return new TriggerActionMap()
    {
        // SwitchCoolトリガに対するアクション
        { SwitchCoolTrigger.Instance.Name, this.SwitchCoolTriggerHandler },
        // SwitchDryトリガに対するアクション
        { SwitchDryTrigger.Instance.Name, this.SwitchDryTriggerHandler },
    };
}


SwitchCool トリガを受信した場合は、Cool 状態への遷移を要求します。
SwitchDry トリガを受信した場合は、Dry 状態への遷移を要求します。

private void SwitchCoolTriggerHandler(TriggerActionArgs args)
{
    // コンテキスト(ステートマシン)の取得
    var context = args.Context;

    // Cool状態への状態遷移を要求
    context.ChangeState(CoolState.Instance);
}

private void SwitchDryTriggerHandler(TriggerActionArgs args)
{
    // コンテキスト(ステートマシン)の取得
    var context = args.Context;

    // Dry状態への状態遷移を要求
    context.ChangeState(DryState.Instance);
}


ソース全体を示します。

public sealed class HeatState : State
{
    // シングルトンインスタンス
    public static HeatState Instance { get; private set; } = new HeatState();

    // コンストラクタ
    private HeatState() : base("Heat")
    {
        this.OnDo += this.DoEventHandler;
    }

    // トリガアクションハッシュテーブル生成
    protected override TriggerActionMap GenerateTriggerActionMap()
    {
        return new TriggerActionMap()
        {
            { SwitchCoolTrigger.Instance.Name, this.SwitchCoolTriggerHandler },
            { SwitchDryTrigger.Instance.Name, this.SwitchDryTriggerHandler },
        };
    }

    // Doイベントハンドラ
    private void DoEventHandler(StateMachine context)
    {
        var stm = context.GetAs<RunningStateMachine>();

        var model = stm.Model;

        model.HeatControl();
    }

    // SwitchCoolトリガハンドラ
    private void SwitchCoolTriggerHandler(TriggerActionArgs args)
    {
        var context = args.Context;

        context.ChangeState(CoolState.Instance);
    }

    // SwitchDryトリガハンドラ
    private void SwitchDryTriggerHandler(TriggerActionArgs args)
    {
        var context = args.Context;

        context.ChangeState(DryState.Instance);
    }
}


DryState クラス

DryState クラスでは、Do イベントハンドラで除湿制御を行うため、モデル(AirConditioner)の除湿制御処理(DryControl)を呼び出します。

private void DoEventHandler(StateMachine context)
{
    // 親ステートマシン(RunningStateMachine)の取得
    var stm = context.GetAs<RunningStateMachine>();

    // モデル(AirConditioner)の取得
    var model = stm.Model;

    // 除湿制御処理呼び出し
    model.DryControl();
}


DryState クラスでは、動作モード(冷房 / 暖房)切り替えスイッチ押下によるトリガを受信できるようにしておきます。

protected override TriggerActionMap GenerateTriggerActionMap()
{
    return new TriggerActionMap()
    {
        // SwitchCoolトリガに対するアクション
        { SwitchCoolTrigger.Instance.Name, this.SwitchCoolTriggerHandler },
        // SwitchHeatトリガに対するアクション
        { SwitchHeatTrigger.Instance.Name, this.SwitchHeatTriggerHandler },
    };
}


SwitchCool トリガを受信した場合は、Cool 状態への遷移を要求します。
SwitchHeat トリガを受信した場合は、Heat 状態への遷移を要求します。

private void SwitchCoolTriggerHandler(TriggerActionArgs args)
{
    // コンテキスト(ステートマシン)の取得
    var context = args.Context;

    // Cool状態への状態遷移を要求
    context.ChangeState(CoolState.Instance);
}

private void SwitchHeatTriggerHandler(TriggerActionArgs args)
{
    // コンテキスト(ステートマシン)の取得
    var context = args.Context;

    // Heat状態への状態遷移を要求
    context.ChangeState(HeatState.Instance);
}


ソース全体を示します。

public sealed class DryState : State
{
    // シングルトンインスタンス
    public static DryState Instance { get; private set; } = new DryState();

    // コンストラクタ
    private DryState() : base("Dry")
    {
        this.OnDo += this.DoEventHandler;
    }

    // トリガアクションハッシュテーブル生成
    protected override TriggerActionMap GenerateTriggerActionMap()
    {
        return new TriggerActionMap()
        {
            { SwitchCoolTrigger.Instance.Name, this.SwitchCoolTriggerHandler },
            { SwitchHeatTrigger.Instance.Name, this.SwitchHeatTriggerHandler },
        };
    }

    // Doイベントハンドラ
    private void DoEventHandler(StateMachine context)
    {
        var stm = context.GetAs<RunningStateMachine>();

        var model = stm.Model;

        model.DryControl();
    }

    // SwitchCoolトリガハンドラ
    private void SwitchCoolTriggerHandler(TriggerActionArgs args)
    {
        var context = args.Context;

        context.ChangeState(CoolState.Instance);
    }

    // SwitchHeatトリガハンドラ
    private void SwitchHeatTriggerHandler(TriggerActionArgs args)
    {
        var context = args.Context;

        context.ChangeState(HeatState.Instance);
    }
}


CleanState クラス

CleanState クラスでは、サブステートマシンとしてCleanStateMachineを持つ必要があります。

// サブステートマシン
public CleanStateMachine SubContext { get; private set; }


CleanStateMachineは、Clena状態に入る(Entryイベント)たびにインスタンスを生成します。
クリーニングモードに入るたびに汚れレベルの解析からやり直すため、Clean状態に入るたび、サブステートマシンの状態を初期状態にリセットする必要があるためです。

private void EntryEventHandler(StateMachine context)
{
    // 親ステートマシン(Model StateMachine)の取得
    var parent = context.GetAs<ModelStateMachine>();

    // サブステートマシン(CleanStateMachine)の生成
    this.SubContext = new CleanStateMachine(parent);
}


また、サブステートマシンの定常的な処理を実行するため、Do イベントハンドラで、サブステートマシンの Update 処理を実行します。
さらに、サブステートマシンが完了状態(CleanFinalState)になっていた場合、クリーニング処理が完了となるため、ステートマシンにRunning状態への状態遷移を要求します。
このとき、エフェクトとしてCleanEndEffectを指定します。

private void DoEventHandler(StateMachine context)
{
    // サブステートマシンの更新
    this.SubContext.Update();

    // サブステートマシンの状態がクリーニング完了状態(CleanFinalState)
    if (this.SubContext.CurrentState is CleanFinalState)
    {
        // 完了遷移で実行するエフェクト(CleanEndEffect)を取得
        var effect = CleanEndEffect.Instance;

        // Running状態への状態遷移を要求
        context.ChangeState(RunningState.Instance, effect);
    }
}


CleanState クラスでは、ストップスイッチ押下によるトリガを受信できるようにしておきます。

protected override TriggerActionMap GenerateTriggerActionMap()
{
    return new TriggerActionMap()
    {
        // SwitchStopトリガに対するアクション
        { SwitchStopTrigger.Instance.Name, this.SwitchStopTriggerHandler },
    };
}


SwitchStop トリガを受信した場合は、Stop 状態への遷移を要求し、その際に Trigger に設定された Effect をパラメータとして受け渡します。

private void SwitchStopTriggerHandler(TriggerActionArgs args)
{
    // コンテキスト(ステートマシン)の取得
    var context = args.Context;

    // 状態遷移時に実行するEffectを取得
    var effect = args.Trigger.Effect;

    // Stop状態への状態遷移を要求
    context.ChangeState(StopState.Instance, effect);
}


ソース全体を示します。

public sealed class CleanState : State
{
    // シングルトンインスタンス
    public static CleanState Instance { get; private set; } = new CleanState();

    // サブステートマシン
    public CleanStateMachine SubContext { get; private set; }

    // コンストラクタ
    private CleanState() : base("Clean")
    {
        this.OnEntry += this.EntryEventHandler;
        this.OnDo += this.DoEventHandler;
    }

    // トリガアクションハッシュテーブル生成
    protected override TriggerActionMap GenerateTriggerActionMap()
    {
        return new TriggerActionMap()
        {
            { SwitchStopTrigger.Instance.Name, this.SwitchStopTriggerHandler },
        };
    }

    // Entryイベントハンドラ
    private void EntryEventHandler(StateMachine context)
    {
        var parent = context.GetAs<ModelStateMachine>();

        this.SubContext = new CleanStateMachine(parent);
    }

    // Doイベントハンドラ
    private void DoEventHandler(StateMachine context)
    {
        this.SubContext.Update();

        if (this.SubContext.CurrentState is CleanFinalState)
        {
            var effect = CleanEndEffect.Instance;

            context.ChangeState(RunningState.Instance, effect);
        }
    }

    // SwitchStopトリガハンドラ
    private void SwitchStopTriggerHandler(TriggerActionArgs args)
    {
        var context = args.Context;

        var effect = args.Trigger.Effect;

        context.ChangeState(StopState.Instance, effect);
    }
}


StainLevelAnalysisState クラス

StainLevelAnalysisState クラスでは、Doイベントハンドラで汚れレベルを解析し、解析が完了したら汚れレベルに応じたクリーニングモード(LightClean / DeepClean)への遷移を要求します。

private void DoEventHandler(StateMachine context)
{
    // 親ステートマシン(CleanStateMachine)の取得
    var stm = context.GetAs<CleanStateMachine>();

    // モデル(AirConditioner)の取得
    var model = stm.Model;

    // 汚れレベル解析処理呼び出し
    var level = model.StainLevelAnalys();

    // 汚れレベル判定
    switch (level)
    {
        case StainLevel.Unknown:    // 未確定
            /* Nothing to do */
            break;
        case StainLevel.Low:    // 汚れレベル低
            // LightClean状態への状態遷移を要求
            stm.ChangeState(LightCleanState.Instance);
            break;
        case StainLevel.High:   // 汚れレベル高
            // DeepClean状態への状態遷移を要求
            stm.ChangeState(DeepCleanState.Instance);
            break;
        default:
            /* Nothing to do */
            break;
    }
}


ソース全体を示します。

public sealed class StainLevelAnalysisState : State
{
    // シングルトンインスタンス
    public static StainLevelAnalysisState Instance { get; private set; } = new StainLevelAnalysisState();

    // コンストラクタ
    private StainLevelAnalysisState() : base("Stain Level AnalysisState")
    {
        this.OnDo += this.DoEventHandler;
    }

    // トリガアクションハッシュテーブル生成
    protected override TriggerActionMap GenerateTriggerActionMap()
    {
        return new TriggerActionMap()
        {
        };
    }

    // Doイベントハンドラ
    private void DoEventHandler(StateMachine context)
    {
        var stm = context.GetAs<CleanStateMachine>();

        var model = stm.Model;

        var level = model.StainLevelAnalys();

        switch (level)
        {
            case StainLevel.Unknown:
                /* Nothing to do */
                break;
            case StainLevel.Low:
                stm.ChangeState(LightCleanState.Instance);
                break;
            case StainLevel.High:
                stm.ChangeState(DeepCleanState.Instance);
                break;
            default:
                /* Nothing to do */
                break;
        }
    }
}


DeepCleanState クラス

DeepCleanState クラスでは、Doイベントハンドラで入念クリーニング処理を実行し、クリーニングが完了したらクリーニング完了(CleanFinal)状態への遷移を要求します。

private void DoEventHandler(StateMachine context)
{
    // 親ステートマシン(CleanStateMachine)の取得
    var stm = context.GetAs<CleanStateMachine>();

    // モデル(AirConditioner)の取得
    var model = stm.Model;

    // 入念クリーニング制御処理呼び出し
    var result = model.DeepCleanControl();

    // クリーニング処理完了
    if (result == true)
    {
        // CleanFinal状態への状態遷移を要求
        stm.ChangeState(CleanFinalState.Instance);
    }
}


ソース全体を示します。

public sealed class DeepCleanState : State
{
    // シングルトンインスタンス
    public static DeepCleanState Instance { get; private set; } = new DeepCleanState();

    // コンストラクタ
    private DeepCleanState() : base("Deep Clean")
    {
        this.OnDo += this.DoEventHandler;
    }

    // トリガアクションハッシュテーブル生成
    protected override TriggerActionMap GenerateTriggerActionMap()
    {
        return new TriggerActionMap()
        {
        };
    }

    // Doイベントハンドラ
    private void DoEventHandler(StateMachine context)
    {
        var stm = context.GetAs<CleanStateMachine>();

        var model = stm.Model;

        var result = model.DeepCleanControl();

        if (result == true)
        {
            stm.ChangeState(CleanFinalState.Instance);
        }
    }
}


LightCleanState クラス

LightCleanState クラスでは、Doイベントハンドラであっさりクリーニング処理を実行し、クリーニングが完了したらクリーニング完了(CleanFinal)状態への遷移を要求します。

private void DoEventHandler(StateMachine context)
{
    // 親ステートマシン(CleanStateMachine)の取得
    var stm = context.GetAs<CleanStateMachine>();

    // モデル(AirConditioner)の取得

    // あっさりクリーニング制御処理呼び出し
    var result = model.LightCleanControl();

    // クリーニング処理完了
    if (result == true)
    {
        // CleanFinal状態への状態遷移を要求
        stm.ChangeState(CleanFinalState.Instance);
    }
}


ソース全体を示します。

public sealed class LightCleanState : State
{
    // シングルトンインスタンス
    public static LightCleanState Instance { get; private set; } = new LightCleanState();

    // コンストラクタ
    private LightCleanState() : base("Light Clean")
    {
        this.OnDo += this.DoEventHandler;
    }

    // トリガアクションハッシュテーブル生成
    protected override TriggerActionMap GenerateTriggerActionMap()
    {
        return new TriggerActionMap()
        {
        };
    }

    // Doイベントハンドラ
    private void DoEventHandler(StateMachine context)
    {
        var stm = context.GetAs<CleanStateMachine>();

        var model = stm.Model;

        var result = model.LightCleanControl();

        if (result == true)
        {
            stm.ChangeState(CleanFinalState.Instance);
        }
    }
}


CleanFinalState クラス

CleanFinalStateクラスは、CleanStateMachineの最終状態のため、特に何もしません。 ソース全体を示します。

public sealed class CleanFinalState : State
{
    public static CleanFinalState Instance { get; private set; } = new CleanFinalState();

    private CleanFinalState() : base("Clean Final")
    {
    }

    protected override TriggerActionMap GenerateTriggerActionMap()
    {
        return new TriggerActionMap()
        {
        };
    }
}


次回予告

今回で状態遷移部分はすべて実装できたので、次回はエアコンのモデル部分(AirConditionerクラス)の実装を行っていきます。

an-embedded-engineer.hateblo.jp