HeadFirstデザインパターン 第6章CommandパターンをC#で軽く実装。
自分のお勉強用 : HeadFirstデザインパターン 第6章CommandパターンをC#で軽く実装。
C#のおさらいとCommandパターンの感触を掴むため、
書籍「HeadFirstデザインパターン」の第6章Commandパターンを適当に実装。
ファイル一覧
- CeilingFan.cs
- ICommand.cs
- Light.cs
- NoCommand.cs
- Program.cs
- RemoteControl.cs
- RemoteLoader.cs
実装
前述のファイル一覧の順番とは異なります。まずはインターフェイスから。
ICommand.cs
- namespace csConsole
- {
- interface ICommand
- {
- void Execute();
- void Undo();
- }
- }
Light.cs : コンクリートとレシーバーその1
- namespace csConsole
- {
- class Light // レシーバー部分
- {
- public Light(){}
- public void on() => Console.WriteLine("ライトオン です。");
- public void off() => Console.WriteLine("ライトOFF です。");
- }
- class LightOnCommand : ICommand // コンクリート部分
- {
- Light light;
- public LightOnCommand(Light light) => this.light = light;
- public void Execute() => light.on();
- public void Undo() => light.off();
- }
- class LightOffCommand : ICommand // コンクリート部分
- {
- Light light;
- public LightOffCommand(Light light) => this.light = light;
- public void Execute() => light.off();
- public void Undo() => light.on();
- }
- }
CeilingFan : コンクリートとレシーバーその2
- {
- class CeilingFan
- {
- public const int HIGH = 3;
- public const int MEDIUM = 2;
- public const int OFF = 0;
- int speed;
- public CeilingFan() => speed = OFF;
- public void high() => speed = HIGH;
- public void medium() => speed = MEDIUM;
- public int getSpeed() => speed;
- }
- class CeilingFanHighCommand : ICommand
- {
- CeilingFan CeilingFan;
- int prevSpeed;
- public CeilingFanHighCommand(CeilingFan ceilingFan) => CeilingFan = ceilingFan;
- public void Execute()
- {
- this.prevSpeed = CeilingFan.getSpeed();
- CeilingFan.high();
- }
- public void Undo()
- {
- switch (prevSpeed)
- {
- case CeilingFan.HIGH:
- CeilingFan.high();
- break;
- case CeilingFan.MEDIUM:
- CeilingFan.medium();
- break;
- }
- }
- }
- class CeilingFanMediumCommand : ICommand
- {
- CeilingFan CeilingFan;
- int prevSpeed;
- public CeilingFanMediumCommand(CeilingFan ceilingFan) => CeilingFan = ceilingFan;
- public void Execute()
- {
- this.prevSpeed = CeilingFan.getSpeed();
- CeilingFan.medium();
- }
- public void Undo()
- {
- switch (prevSpeed)
- {
- case CeilingFan.HIGH:
- CeilingFan.high();
- break;
- case CeilingFan.MEDIUM:
- CeilingFan.medium();
- break;
- }
- }
- }
- }
NoCommand.cs : コンクリートとレシーバーその3
- namespace csConsole
- {
- class NoCommand : ICommand
- {
- public void Execute() => Console.WriteLine("NoCommand");
- public void Undo() => Console.WriteLine("NoCommand : Undo");
- }
- }
invoker : 記事的にはリモコンクラス
- namespace csConsole
- {
- class RemoteControl
- {
- ICommand[] onCommands;
- ICommand[] offCommands;
- Stack < ICommand > undoCmds; //「<」の前後に半角スペース入れてます。ブログ化したら消えたので。
- // コンストラクタ
- public RemoteControl()
- {
- // 例題通り7個のボタン
- this.onCommands = new ICommand[7];
- this.offCommands = new ICommand[7];
- undoCmds = new Stack
(); // 初期化 ICommand noCommand = new NoCommand(); for (int i = 0 ; i < 7; i++) { this.onCommands[i]=noCommand; this.offCommands[i]=noCommand; } } } public void setCommand( int slot, ICommand onCmd, ICommand offCmd ) { this.onCommands[slot]=onCmd; this.offCommands[slot]=offCmd; } public void onPush( int slot ) { this.onCommands[slot].Execute(); this.undoCmds.Push(this.onCommands[slot]); } public void offPush(int slot) { this.offCommands[slot].Execute(); this.undoCmds.Push(this.offCommands[slot]); } public void UndoPush() { this.undoCmds.Pop().Undo(); } }
client : 記事的にはリモートローダー(リモコン定義)
- namespace csConsole
- {
- class RemoteLoader
- {
- static public void setRemoteControler(RemoteControl remote)
- {
- // コンクリートコマンドの作成
- // Light
- Light light = new Light();
- LightOnCommand lightOnCommand = new LightOnCommand(light);
- LightOffCommand lightOffCommand = new LightOffCommand(light);
- // CeilingFan
- CeilingFan ceilingFan = new CeilingFan();
- CeilingFanHighCommand ceilingFanHighCommand = new CeilingFanHighCommand(ceilingFan);
- CeilingFanMediumCommand ceilingFanMediumCommand = new CeilingFanMediumCommand(ceilingFan);
- // コマンドをリモコンに設定
- remote.setCommand(0, lightOnCommand, lightOffCommand);
- remote.setCommand(1, ceilingFanHighCommand, ceilingFanMediumCommand);
- }
- }
- }
プログラムのMainクラス
- namespace csConsole
- {
- class Program
- {
- static void Main(string[] args)
- {
- // リモコン生成
- RemoteControl remote = new RemoteControl();
- // リモコンの内容設定
- RemoteLoader.setRemoteControler(remote);
- remote.onPush(0); // ここはLightオン。
- remote.UndoPush(); // LightオンのUndo = オフ。
- remote.onPush(1); //HIGH
- remote.offPush(1); //MEDIUM
- remote.UndoPush(); //MEDIUMオブジェクトの中のUNDOでHIGHを呼ぶ。
- Console.WriteLine("リモコン終了");
- }
- }
- }
所感
コードの構造はざっくり把握できたかと。Undo処理については「Undoとはなにか」という哲学になりそうな感じ。
とりあえずFILOを簡単に使いたかったからStackを選定したけども、
これだと無限にStackするし、実用のときはなんらか工夫が必要ですね。
ところでGoFの本も結城本も、クラス図でClientクラスからInvokerクラスへの関連線が出てないのって
どうしてなんだろうか。
インスタンス持ちますよねぇ。
コメント
コメントを投稿