I'm trying to implement the command pattern, so it works like this:
- There is a base class
Command<T>, from which all other commands inherit. - A command can be executed on a class deriving from an
Actor. - Each interface defines an action an
Actorcan perform. E.g.IMovableorITurnable. - Each command class acts on a specific interface. E.g.
Command<IMovable>. - Actors implement interfaces, which define what actions they can perform.
Here is how I tried implementing it:
// base interface for all action interfaces
public interface ICommandable { }
// interface for a move action
public interface IMovable : ICommandable
{
void Move();
}
// base actor class
public class Actor : ICommandable
{
public void ExecuteCommand(ICommand<ICommandable> command)
{
(command as Command<ICommandable>).Execute(this);
}
}
// an actor which can be moved
public class MovableActor: Actor, IMovable
{
public void Move()
{
Console.WriteLine("Move");
}
}
// an interface for commands
public interface ICommand<out T> { }
// base command class
public class Command<T> : ICommand<T> where T : ICommandable
{
public virtual void Execute(T robot) { }
}
// move command
public class MoveCommand : Command<IMovable>
{
public override void Execute(IMovable actor)
{
actor.Move();
}
}
This is an example of what I'm trying to do:
MovableActor actor = new MovableActor();
Command<IMovable> cmd = new MoveCommand();
actor.ExecuteCommand(cmd);
The issue with my implementation is that the ICommand interface has to use the out keyword for its parameter. I did some reading and I understand why that is, but I don't know how to achieve what I described. How can I implement this?
If this is not possible, how should I change my description, so it's as close to this one as possible, but works?
ICommandat all. If I remove it, your code still compiles fine. It also compiles fine if I remove theoutMoveCommandand pass it toExecuteCommand()of theMovableActor, it doesn't work.MoveCommand.Executemust be given anIMovable-- that method depends on having anIMovable. However, you're allowed to pass anything toActor.ExecuteCommand, even a command such as anICommand<ITurntable>: there's nothing stopping you doing this. But if you did that, and calledMoveCommand.ExecuteCommandwith anICommand<ITurntable>,MoveCommand.Executewould fail, because it wants anIMovable.