ほとんどの C# コマンド パターンの実装は、Java の実装とほぼ同じです。これらの実装では通常、ICommand インターフェイスを使用します。
public interface ICommand
{
void Execute();
}
そして、すべてのコマンド クラスが強制的にインターフェイスを実装します。私はこのソリューションに問題はありませんが、個人的にはあまり多くのクラスを作成するのは好きではなく、代わりに .NET デリゲートを使用することを好みます (Java にはデリゲートはありません)。Action デリゲートは通常、メソッド参照が 1 つだけ必要な場合にこのトリックを実行します。
public class Prog
{
public Prog()
{
var factory = new CommandFactory();
factory.Register("A", () => new A().DoA);
factory.Register("B", () => new B().DoB);
factory.Register("C", DoStuff);
factory.Execute("A");
}
public static void DoStuff()
{
}
}
public class CommandFactory
{
private readonly IDictionary<string, Action> _commands;
public void Register(string commandName, Action action)
{
_commands.Add(commandName, action);
}
public Action GetCommand(string commandName)
{
_commands[commandName];
}
public void Execute(string commandName)
{
GetCommand(commandName)();
}
}
public class A
{
public void DoA()
{
}
}
public class B
{
public void DoB()
{
}
}
コマンド インターフェイスに次のような複数のメソッドが必要な場合:
public interface ICommand
{
void Execute();
void Undo();
}
次のようなラッパー クラスを使用できます。
public class Command
{
public Command(Action execute, Action undo)
{
Execute = execute;
Undo = undo;
}
public Action Execute { get; protected set; }
public Action Undo { get; protected set; }
}
または(どちらでも構いません)
public class Command
{
private readonly Action _execute;
private readonly Action _undo;
public Command(Action execute, Action undo)
{
_execute = execute;
_undo = undo;
}
public void Execute()
{
_execute();
}
public void Undo()
{
_undo();
}
}
(これは、既に使用しているレガシーなものがある場合は ICommand を実装することさえできます。インターフェイスを使用する場合、ファクトリは Command クラスの代わりにインターフェイスを使用する必要があります)
このようなラッパーを使用すると、サポートするアクションごとにコマンド クラスを作成する必要がなくなります。次の例は、ラッパー クラスの使用方法を示しています。
public class Prog2
{
public Prog2()
{
var factory = new CommandFactory2();
factory.Register("A", new Lazy<Command>(
()=>
{
var a = new A();
return new Command(a.DoA, a.UndoA);
}));
factory.Register("B", new Lazy<Command>(
() =>
{
var c = new B();
return new Command(c.DoB, c.DoB);
}));
factory.Register("C", new Lazy<Command>(
() => new Command(DoStuff, UndoStuff)));
factory.Execute("A");
}
public static void DoStuff()
{
}
public static void UndoStuff()
{
}
}
public class CommandFactory2
{
private readonly IDictionary<string, Lazy<Command>> _commands;
public void Register(string commandName, Lazy<Command> lazyCommand)
{
_commands.Add(commandName, lazyCommand);
}
public void Register(string commandName, Action execute, Action undo)
{
_commands.Add(commandName, new Lazy<Command>(() => new Command(execute, undo)));
}
public Command GetCommand(string commandName)
{
return _commands[commandName].Value;
}
public void Execute(string commandName)
{
GetCommand(commandName).Execute();
}
public void Undo(string commandName)
{
GetCommand(commandName).Undo();
}
}
public class A
{
public void DoA()
{
}
public void UndoA()
{
}
}
public class B
{
public void DoB()
{
}
public void UndoB()
{
}
}
ご覧のとおり、複数のメソッド (Execute、Undo など) がある場合でも、インターフェイスを実装する必要はありません。Execute メソッドと Undo メソッドは異なるクラスに属している可能性があることに注意してください。より自然に感じられる方法で自由にコードを構成でき、コマンド パターンを使用することもできます。