基本的には読み下しながらのメモ
WikiPediaから
WikipediaのCommand Patternより
Four terms always associated with the command pattern are command, receiver, invoker and client. A command object knows about receiver and invokes a method of the receiver. Values for parameters of the receiver method are stored in the command. The receiver object to execute these methods is also stored in the command object by aggregation. The receiver then does the work when the execute() method in command is called. An invoker object knows how to execute a command, and optionally does bookkeeping about the command execution. The invoker does not know anything about a concrete command, it knows only about the command interface. Invoker object(s), command objects and receiver objects are held by a client object, the client decides which receiver objects it assigns to the command objects, and which commands it assigns to the invoker. The client decides which commands to execute at which points. To execute a command, it passes the command object to the invoker object.
Deeply翻訳
コマンドパターンには、コマンド、レシーバ、インボーカ、クライアントの4つの用語が常に関連付けられています。コマンドオブジェクトは、レシーバを認識し、レシーバのメソッドを呼び出す。コマンドには、Receiver のメソッドのパラメータの値が格納される。また、これらのメソッドを実行するためのReceiverオブジェクトも集約してコマンドオブジェクトに格納される。そして、コマンドの execute()メソッドが呼ばれると、Receiver が処理を行う。invoker オブジェクトは、コマンドの実行方法を知っており、オプションとしてコマンドの実行に関する記帳を行う。インボーカは具体的なコマンドについては何も知らず、コマンドのインターフェイスについてのみ知っています。インボーカオブジェクト、コマンドオブジェクト、レシーバオブジェクトはクライアントオブジェクトによって保持され、クライアントはどのレシーバオブジェクトをコマンドオブジェクトに割り当てるか、どのコマンドをインボーカに割り当てるかを決定します。クライアントは、どのコマンドをどの時点で実行するかを決定する。コマンドを実行するには、コマンドオブジェクトをインボーカオブジェクトに渡します。
www.DeepL.com/Translator (無料版)で翻訳しました。
分からないので、整理
コマンドパターンは4つに別れて
- Command:
- Receiverの認識
- Receiverの呼び出し
- Receiverのパラメータの保持
- 呼び出すReceiverを集約する
- Receiver
- Command中でexecute()の呼び出しと共に実行される
- Invoker
- Commandの実行の仕方を知っている
- 記帳(bookkeeping=履歴?)を行うこともある
- 実際のCommandの内容は知っておらず、Commandのインタフェースを知っているのみ
- Client
- Command、Receive、Invokerを保持する
- どのReceiverをCommandに渡し、どのCommandをInvokerに渡すかを決定する
- どこでコマンドを実行するかを決める
- Commandを実行するには、Invokerにcommandを渡す
かな?
Wikipediaのサンプル
Receiverから見る。特に何もなくて普通のインタフェースとクラス。
/* An interface that defines actions that the receiver can perform */
public interface ISwitchable
{
void PowerOn();
void PowerOff();
}
/* The Receiver class */
public class Light : ISwitchable
{
public void PowerOn()
{
Console.WriteLine("The light is on");
}
public void PowerOff()
{
Console.WriteLine("The light is off");
}
}
続きまして、Command。
こちらはクラス内にReceiverのSwitchableを持っていて実行している。ただし、インタフェースのみなので実際に何を実行するかは知らない。
また、インタフェースとしてはExecuteを持っている。
下記はCloseSwitchCommandのみだが、他にOpenSwitchCommandがある。
public interface ICommand
{
void Execute();
}
/* The Command for turning off the device - ConcreteCommand #1 */
public class CloseSwitchCommand : ICommand
{
private ISwitchable _switchable;
public CloseSwitchCommand(ISwitchable switchable)
{
_switchable = switchable;
}
public void Execute()
{
_switchable.PowerOff();
}
}
続きましてInvoker。複数のCommand(openedCommandとclosedCommand)を持っていて、Open、Closeが呼び出されるとそれぞれのCommandが実行される(Execute()が呼ばれる)
/* The Invoker class */
public class Switch
{
ICommand _closedCommand;
ICommand _openedCommand;
public Switch(ICommand closedCommand, ICommand openedCommand)
{
this._closedCommand = closedCommand;
this._openedCommand = openedCommand;
}
// Close the circuit / power on
public void Close()
{
this._closedCommand.Execute();
}
// Open the circuit / power off
public void Open()
{
this._openedCommand.Execute();
}
}
最後、Client。順に
- Light(Receiver)の作成(L.8)
- CloseSwitch、OpenSwitch(Command) (L.10〜12)
- Invoker(Switch)を作成と同時に、ReceiverとCommandに渡している。(L.14,15)
- 3.で宣言したInvokerに対してOepn、Closeを実行している(L.20,25)
なお、 @ 変数は[逐次識別子] と言って予約語のswitchを変数名として使うために宣言しているらしい・・・知らんがな
/* The test class or client */
internal class Program
{
public static void Main(string[] arguments)
{
string argument = arguments.Length > 0 ? arguments[0].ToUpper() : null;
ISwitchable lamp = new Light();
// Pass reference to the lamp instance to each command
ICommand switchClose = new CloseSwitchCommand(lamp);
ICommand switchOpen = new OpenSwitchCommand(lamp);
// Pass reference to instances of the Command objects to the switch
Switch @switch = new Switch(switchClose, switchOpen);
if (argument == "ON")
{
// Switch (the Invoker) will invoke Execute() on the command object.
@switch.Open();
}
else if (argument == "OFF")
{
// Switch (the Invoker) will invoke the Execute() on the command object.
@switch.Close();
}
else
{
Console.WriteLine("Argument \"ON\" or \"OFF\" is required.");
}
}
個人的な結論
- Receiver: 単なるクラス。ただし、操作はインタフェース経由で
- Command: Receiverを実行する。実行のためのインタフェースメソッドexecuteをもち、そこから実行する
- Invoker: Commandを実行する。Receiverについては何も知らず、ただCommandを自分の順番で実行する
- Client: ReceiverやCommand、Invokerの初期設定、呼び出し側に呼び出し側を渡してInvokerを実行させる
呼び出し関係的には Client → Invoker → Command → Receiver って感じなのかな。