コマンドデザインパターン2

コマンド設計パターンの実現テストします

シナリオ

家電リモコンを例にコマンドを割り当てる方法をみていきましょう

クラス図

RemoteLoaderコード

リモコンのスロットにロードされる多数のコマンドオブジェクトを作成します
コマンドオブジェクトは、ホームオートメーションデバイスのリクエストをカプセル化します

namespace P203Command
{
    public class RemoteLoader
    {
        public static void Main()
        {
            RemoteLoader remoteLoader = new RemoteLoader();
            remoteLoader.Run();
        }

        public void Run()
        {
            RemoteControl remoteControl = new RemoteControl();

            // 全てのデバイスをそれぞれ適切な場所に作成します
            Light livingRoomLight = new Light("リビングルーム");
            Light kitchenLight = new Light("キッチン");

            CeilingFan ceilingFan = new CeilingFan("リビングルーム");


            GarageDoor garageDoor = new GarageDoor("ガレージ");

            Stereo stereo = new Stereo("リビングルーム");

            // 全てのLightコマンドオブジェクトを作成します
            LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight);
            LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight);
            LightOnCommand kitchLightOn = new LightOnCommand(kitchenLight);
            LightOffCommand kitchLightOff = new LightOffCommand(kitchenLight);

            // シーリングファン用のOnコマンドとOffコマンドを作成します
            CeilingFanOnCommand ceilingFanOn = new CeilingFanOnCommand(ceilingFan);
            CeilingFanOffCommand ceilingFanOff = new CeilingFanOffCommand(ceilingFan);

            // ガレージ用のUpコマンドとDownコマンドを作成します
            GarageDoorUpCommand garageDoorUp = new GarageDoorUpCommand(garageDoor);
            GarageDoorDownCommand garageDoorDown = new GarageDoorDownCommand(garageDoor);

            // オーディオ用のOnコマンドとOffコマンドを作成します
            StereoOnWithCDCommand stereoOnWithCD = new StereoOnWithCDCommand(stereo);
            StereoOffWithCDCommand stereoOffWithCD = new StereoOffWithCDCommand(stereo);

            // 全てのコマンドが作成できたので、コマンドをリモコンのスロットにロードできます
            remoteControl.SetCommand(0, livingRoomLightOn, livingRoomLightOff);
            remoteControl.SetCommand(1, kitchLightOn, kitchLightOff);
            remoteControl.SetCommand(2, ceilingFanOn, ceilingFanOff);
            remoteControl.SetCommand(3, stereoOnWithCD, stereoOffWithCD);

            // ここで先ほどのToString()メソッドを使ってリモコンの各スロットと割り当てられたコマンドを出力します
            // ここでは、ToString()は自動的に呼び出されるので、明治的にToString()を呼び出す必要はありません
            Console.WriteLine(remoteControl);

            // 問題ないようです
            // 実行準備が整いました!これで各スロットに対するOnボタンとOffボタンを押してテストしましょう
            remoteControl.OnButtonWasPushed(0);
            remoteControl.OffButtonWasPushed(0);

            remoteControl.OnButtonWasPushed(1);
            remoteControl.OffButtonWasPushed(1);

            remoteControl.OnButtonWasPushed(2);
            remoteControl.OffButtonWasPushed(2);

            remoteControl.OnButtonWasPushed(3);
            remoteControl.OffButtonWasPushed(3);
        }
    }
}

コマンドインターフェイスのコード

全てのRemoteControlコマンドはICommandインターフェースを実装しています
このインターフェースはExecute()というメソッドを1つだけ持ちます
コマンドは、特定のベンダークラスの一連のアクションをカプセル化します
リモコンは、Execute()メソッドを呼び出してアクションを起動します

using System;
namespace P203Command
{
    /// <summary>
    /// ICommand
    /// 全てのコマンドのためのインターフェースを宣言します
    /// コマンドはExecute()メソッドで起動し、Execute()メソッドは、
    /// レシーバーにアクションを実行するように依頼します
    /// このインターフェースには、Undo()メソッドもあります
    /// </summary>
    public interface ICommand
    {
        void Execute();
        void Undo();
    }
}

Lightコード

ベンダークラスを使って、デバイスを制御する実際のホームオートメーション処理を実行します
ここでは例として、Lightクラスを使用しています

namespace P203Command
{
    /// Receiver
    /// リクエストに対処するために必要な処理の実行方法を
    /// 知っています
    /// どのクラスでもReceiverとして動作できます
    public class Light
    {
        private string name;

        public Light(string name)
        {
            this.name = name;
        }

        internal void Off()
        {
            Console.WriteLine($"{name}照明を消しました");
        }

        internal void On()
        {
            Console.WriteLine($"{name}照明を点けました");
        }
    }
}

LightのCommandのコード

ICommandインターフェースを利用して、リモコンのボタンを押すと起動できるアクションを簡単なコマンドオブジェクトで実装します
コマンドオブジェクトはベンダークラスのインスタンスであるオブジェクトへの参照を保持し、そのオブジェクトの1つ以上のメソッドを呼び出すExecute()メソッドを実装します
ここでは照明のOnとOffを行う2つのクラスを表しています

LightOnCommandコード

using System;
namespace P203Command
{
    /// <summary>
    ///  ConcreteCommand
    ///  アクションとReceiverの結びつきを定義します
    ///  InvokerがExecute()メソッドを呼び出してリクエストを行い、
    ///  ConcreteCommandがReceiverの1つ以上の悪所運を呼び出しています
    /// </summary>
    public class LightOnCommand : ICommand
    {
        Light light;

        public LightOnCommand(Light light)
        {
            this.light = light;
        }

        /// <summary>
        /// リクエストの実行に必要なレシーバーのアクションを起動します
        /// </summary>
        public void Execute()
        {
            light.On();
        }

        public void Undo()
        {
            throw new NotImplementedException();
        }
    }
}

LightOffCommandコード

using System;
using System.Collections.Generic;

namespace P203Command
{
    public class LightOffCommand : ICommand
    {
        private Light light;

        public LightOffCommand()
        {
        }

        public LightOffCommand(Light light)
        {
            this.light = light;
        }

        public void Execute()
        {
            light.Off();
        }

        public void Undo()
        {
            throw new NotImplementedException();
        }
    }
}

結果

—– リモコン —–
[スロット0] LightOnCommand LightOffCommand
[スロット1] LightOnCommand LightOffCommand
[スロット2] CeilingFanOnCommand CeilingFanOffCommand
[スロット3] StereoOnWithCDCommand StereoOffWithCDCommand
[スロット4] NoCommand NoCommand
[スロット5] NoCommand NoCommand
[スロット6] NoCommand NoCommand

リビングルーム照明を点けました
リビングルーム照明を消しました
キッチン照明を点けました
キッチン照明を消しました
リビングルームシーリングファンをOnにしました
シーリングファンをOnにしました
ステレオをOnにました
CDをセットました
ボリュームを22にしました
ステレオをOffにました

参考