first of all sorry if I'll be using a messy terminology, I'm still learning a lot about the Command pattern and C#.
I'm trying to implement the command pattern in Unity3D using C#, specifically this implementation readapted to my case.
Given the Command.cs and the GameController.cs scripts, I've created a DoThing class, inheriting from the Command class, implemented with the following code:
public class DoThing : Command
{
public string name;
public int healthPoints;
public DoThing(string name, int healthPoints)
{
this.name = name;
this.healthPoints = healthPoints;
}
}
Now, since I passed some arguments to the Commands through a constructor (name, healthPoints), I'd want to extract those from another script.
I tried (successfully) to pass the arguments to a command in the following line and to save the command in a stack:
var doCommand = new DoThing("asdf", 123);
Stack<Command> listOfCommands = new Stack<Command>();
listOfCommands.Push(doCommand);
And I tried (successfully) retrieving those arguments in the watch window, during code execution:
listOfCommands.Peek().name //returns "asdf"
But then this doesn't work in the script, meaning that the arguments can't be seen:
Debug.Log(listOfCommands.Peek().name) //throws error
is there a way to extract the argument?
Since your listOfCommands is a Stack of Command, listOfCommands.Peek() returns a Command which does not have the name variable. You have to check the type of the variable returned by the function and cast it before accessing the variable.
Command command = listOfCommands.Peek();
if(command is DoThing)
{
Debug.Log(((DoThing) command).name);
}
or more compact
if(listOfCommands.Peek() is DoThing doThing)
{
Debug.Log(doThing.name);
}
or
DoThing doThing = listOfCommands.Peek() as DoThing;
if(doThing != null)
{
Debug.Log(doThing.name);
}
From Command pattern wiki:
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.
So if what the DoThing command does is log a message to the console, it should look like this:
public abstract class Command
{
public abstract void Execute();
}
public class DoThing : Command
{
public string name;
public int healthPoints;
public DoThing(string name, int healthPoints)
{
this.name = name;
this.healthPoints = healthPoints;
}
public override void Execute(){
Debug.Log(name);
// whatever else the command does
}
}
And you would call execute on the command.
Related
I am currently trying to make a console for my game, and decided making a class called Command which can then be used to create commands easily was a good idea. I made the class but of course these classes are going to do vastly different thing, as such I was thinking of making a property which would basically act like a function, aka I could construct a command with properties commandName, arguments and then the customizable code block which would then be executed upon writing the command. How would I go about this?
public class Command : MonoBehaviour
{
string inputCommand;
int arguments;
void execution()
{
//this is where to codeblock to be executed upon typing the command would go
}
}
Edit:
I made what seems to be progress but still can't seem to get it right. Also each action needs to be able to have different amounts of arguments (for example "runes.add" needs an integer for runes to add and "updatestore" needs none). Any help would be greatly appreciated
public class Command : MonoBehaviour
{
public string InputCommand { get; set; }
public int Arguments { get; set; }
public Action ExecuteAction { get; set; }
}
public class Commands
{
public List<Command> commandCollection = new List<Command>()
{
new Command()
{
InputCommand = "",
Arguments = 1,
ExecuteAction = new Action(()=>{code to execute goes here})
}
};
}
First of all, you shouldn't derive Command from MonoBehaviour if you want to construct Command with object constructor (not Instantiate).
I think you should make abstract Command class and create commands as classes derived from Command class.
Also what you call "code block" can be done using polymorphism.
So, what you need to do:
Create Command class
public abstract class Command
{
public abstract void Execute(string[] args);
}
Execute method is abstract so we can override realisation of this method in subclasses. This methods takes an array of command arguments as the parameter.
Create some test commands
public class TestCommand : Command
{
public override void Execute(string[] args)
{
Debug.Log("Test command invoked, passed parameters count: " + args.Length);
}
}
Create CommandRegistry class (it's your Commands class)
public class CommandRegistry
{
private Dictionary<string, Command> _commands;
public CommandRegistry()
{
_commands = new Dictionary<string, Command>();
}
public void RegisterCommand(string name, Command command)
{
// You should also check here if command already exists
if(_commands.ContainsKey(name))
{
// Print error here or throw an exception
return;
}
_commands[name] = command;
}
public void RegisterAllCommands()
{
// Add here every new command to register it
RegisterCommand("test", new TestCommand());
}
// Returns false if command not found
public bool ExecuteCommand(string commandName, string[] args)
{
if(_commands.ContainsKey(commandName) == false)
return false;
_commands[commandName].Execute(args);
return true;
}
}
That's it. You need to call ExecuteCommand method to execute a command and pass a name and arguments of the command.
You should check argument count inside a Command.Execute method.
Also if you need to access your game methods/fields (for example to add runes) you should provide static access to this fields/methods or create something like CommandContext class (or GameContext).
An instance of this class will be passed to every command and it contains references to objects that can do things like adding runes.
Then you will need to add a new parameter (CommandContext) to GameRegistry.ExecuteCommand and Command.Execute method.
I am new to unit testing, so pardon me if I am unable to explain this question properly. I am reading a book "The art of Unit Testing 2nd Edition" and trying to implement unit testing in my project. I am currently stuck or confused when testing using mocking (using NSubstitute as the mocking framework).
Here is my scenario:
I have two interfaces ICommand and IUser
public interface ICommand
{
string execute();
}
public interface IUserCalendar
{
string LoadCalendar();
}
I have a class LoadCalendar which implements ICommand:
public class LoadCalendar : ICommand
{
private IUserCalendar user;
public string execute()
{
return this.user.LoadCalendar();
}
public LoadCalendar(IUserCalendar obj)
{
this.user = obj;
}
}
ViewCalendar implements IUserCalendar:
public class Viewer : IUserCalendar
{
public string LoadCalendar()
{
return "Viewer Load Calendar Called";
}
}
Using an agent class I am invoking command for specific request. (Here I am showing only one request LoadCalendar for one user viewer but I have more command and more users)
My client has an invoker object that invokes the command for specific user.
public class Client
{
public Client()
{ }
public string LoadCalendar(ICommand cmd)
{
Invoker invoker = new Invoker(cmd);
return invoker.execute();
}
}
Now I like to test the client class that when it calls for specific user it should return proper object or message.
[Test]
public void client_Load_Calendar_Administrator()
{
IUserCalendar calanedar = Substitute.For<IUserCalendar>();
ICommand cmd = Substitute.For<ICommand>(calanedar);
Client c = new Client();
c.LoadCalendar(cmd, calanedar).Returns(Arg.Any<string>());
}
I don't know where I am doing wrong and it's throwing an error.
NSubstitute.Exceptions.SubstituteException : Can not provide constructor arguments when substituting for an interface.
Any help is really appreciated. Sorry for long question.
The error you're getting:
Can not provide constructor arguments when substituting for an interface.
Is telling you exactly what's wrong.
You're passing in constructor arguments here:
ICommand cmd = Substitute.For<ICommand>(calanedar);
Of course, interfaces never have a constructor. You're trying to interact with your ICommand interface as if it were your concrete LoadCalendar implementation of it.
Furthermore, to be able to unit test a class you always want to have a default (parameterless) constructor. Many mocking frameworks actually require this.
In this case you should probably test against the concrete class and mock/substitute the classes that it uses.
Either that, or you only substitute ICommand simply to have it return a pre-set (string) value. Then you can proceed to verify if the code that consumes your command, actually invokes it and/or does the correct thing with the value it returns.
To illustrate:
[Test]
public void client_Load_Calendar_Administrator()
{
// You are substituting (mocking) the IUserCalendar here, so to test your command
// use the actual implementation
IUserCalendar calendar = Substitute.For<IUserCalendar>();
ICommand cmd = new LoadCalendar(calendar):
// Let the IUserCalendar.LoadCalendar() return a certain string
// Then Assert/Verify that cmd.Execute() returns that same string
}
That's the point of unit testing: you test the smallest piece of functionality by mocking all dependencies. Otherwise it's an integration test.
To test your client:
[Test]
public void client_Load_Calendar_Administrator()
{
ICommand cmd = Substitute.For<ICommand>();
Client c = new Client();
// Let your command return a certain string
// Then verify that your calendar returns that same string
}
EDIT: In case you're interested, the method in NSubstitute that throws this exception:
private void VerifyNoConstructorArgumentsGivenForInterface(object[] constructorArguments)
{
if (constructorArguments != null && constructorArguments.Length > 0)
{
throw new SubstituteException("Can not provide constructor arguments when substituting for an interface.");
}
}
They're pretty clear about it: no constructor arguments for an interface substitute, no matter what.
I've inherited some code that implements WPF Commands as follows:
public ICommand pvToggleSelectMapCommand
{
get
{
return new CommandHandler(() => pvToggleSelectMap(), true);
}
}
This is fine without parameters and doesn't use a generic RelayCommand-like class to set up the command handling. I need to put a parameter into this now, and am struggling to find a simple way to handle on using this way of command handling.
Any suggestions?
Usually, when using some form of delegate ICommand, you can just add an object input parameter to get your CommandParameter object. Try this:
public ICommand pvToggleSelectMapCommand
{
get
{
return new CommandHandler((params) => pvToggleSelectMap(params), true);
}
}
...
public void pvToggleSelectMap(object params) { ... }
Of course, this might not work with your CommandHandler class as you didn't provide any information for that here.
Well, I'm trying to implement command pattern to create interaction with an object.
Almost all of commands that would be created consist of request to an object and response from that object.
So the question is - how to manage this responses?
It's easy to make, when all commands - void. No matter what they are, you can execute them if they implements #executable# interface, so have
void Execute(object params)
But what to do, when their responses have different types? Maybe the command pattern is not right for this project?
ICommandResponse Execute(object params)
You can return an interface with a ResponseType property that gives you information about the concrete response type.
Make use of .NET's built-in command pattern types and lambdas.
First all all, you do not need your own command patetrn interface. Use Action<T>. So, for example, any command called must be of the following signature:
void Command(object params)
Then, for any command that isn't of this form, provide a lambda shim for it, eg:
() => { SomeCommandThatTakesTwoParamsAndRetrunsInt(parms.part1, params.part2); }
The above lambda then complies with the void Command(object params) requirements.
Command execution result may be event.
Example:
class ChangeNameCommand
{
int _id;
string _name;
IRepository _repository;
IEventPublisher _publisher;
public ChangeNameCommand(int id, string name, IRepository repository, IEventPublisher publisher)
{
_id = id;
_name = name;
_repository = repository;
_publisher = publisher;
}
public void Execute()
{
User user = _repository.Get(_id)
user.Name = _name;
_repository.Save(user);
NameChangedEvent e = new NameChangedEvent();
_publisher.Publish(e);
}
}
class UserNameChanged : IHandler<NameChangedEvent>
{
public void Handle(NameChangedEvent e)
{
//TODO...
}
}
Here is the code:
class Class1
{
private Class2 object;
public Class1(Class2 obj) : this(obj.ToString())
{
this.object = obj;
}
}
More specifically, what does the : this part do.
The :this(obj.ToString) causes the constructor code for the constructor defined taking a string parameter to run first. Once it runs, then the constructor code (setting this.object = obj) is executed.
This is covered in MSDN's page on Constructors (the last example set).
Note that, in your code above, as written, this will cause a compiler error. You would also need to have a constructor like the following:
public Class1(string str) // Constructor taking a string, though it could be non-public
{
// Do something with str
}
With this constructor in place, it will get called, perform it's initialization steps, then the first constructor (which sets this.object) will run.
: this(obj.ToString()) calls overloaded version of constructor from same class.
It means that somewhere in this class you have another constructor which takes string as parameter and will be executed alongside current constructor.
class A
{
public A(Class2 obj): this(obj.ToString()) // execute A(string text)
{
// your code
}
public A(string text)
{
// your code
}
}
Class 1 will have another constructor that takes a string parameter.
It calls the constructor that matches that syntax. In your case, I'm assuming there's a constructor that takes a string argument somewhere:
public Class1(string s)
{
}