HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Command pattern with structs

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
withcommandpatternstructs

Problem

I'm using the command pattern to enable actions in my game to be undoable. ICommand defines individual commands, ICommandHandler does the undo-redo logic and might be decorated with other handlers like logging etc.

public interface ICommand
{
    void Execute();
    void Undo();
}

public interface ICommandHandler
{
    void Execute(ICommand command);
    void Undo();
    void Redo();
}

public class CommandHandler : ICommandHandler
{
    Stack _undoStack = new Stack();
    Stack _redoStack = new Stack();

    public void Execute(ICommand command)
    {
        if (command == null)
            throw new ArgumentNullException("command");

        command.Execute();
        _undoStack.Push(command);
        _redoStack.Clear();
    }

    public void Undo()
    {
        if (_undoStack.Count > 0)
        {
            ICommand undoCommand = _undoStack.Pop();
            undoCommand.Undo();
            _redoStack.Push(undoCommand);
        }
    }

    public void Redo()
    {
        if (_redoStack.Count > 0)
        {
            ICommand redoCommand = _redoStack.Pop();
            redoCommand.Execute();
            _undoStack.Push(redoCommand);
        }
    }
}


So far I'm not having any problems. Please correct me if I'm doing anything horribly wrong, but my actual questions is: Can I safely use a struct as a concrete command object or should I use a class?

public struct MoveCameraCommand : ICommand
{
    public CameraController cameraController;
    public Vector2 moveDelta;

    public MoveCameraCommand(CameraController controller, Vector2 moveDelta)
    {
        this.cameraController = controller;
        this.moveDelta = moveDelta;
    }

    public void Execute()
    {
        cameraController.Move(moveDelta);
    }

    public void Undo()
    {
        cameraController.Move(-moveDelta);
    }
}


I've noticed that when using a regular class, I'm generating garbage each frame with my camera, because move commands are issues very often. Since

Solution

It will not work well, I think. The only way to escape boxing on storing is to have a value type collection, so all your commands will need to be of the same type...

Also structs are very specific things, have a look below:

  • Here about Boxing/unboxing.



  • Size/speed issues - try to run this test.



  • See Using Structs:



When you create a struct object using the new operator, it gets created and the appropriate constructor is called. Unlike classes, structs can be instantiated without using the new operator. In such a case, there is no constructor call, which makes the allocation more efficient. However, the fields will remain unassigned and the object cannot be used until all of the fields are initialized.

When a struct contains a reference type as a member, the default constructor of the member must be invoked explicitly, otherwise the member remains unassigned and the struct cannot be used. (This results in compiler error CS0171.)

There is no inheritance for structs as there is for classes. A struct cannot inherit from another struct or class, and it cannot be the base of a class. Structs, however, inherit from the base class Object. A struct can implement interfaces, and it does that exactly as classes do.

Context

StackExchange Code Review Q#131816, answer score: 4

Revisions (0)

No revisions yet.