lundi 30 décembre 2019

Command pattern - Commands that execute the task with a "weight"

I'm currently working on designing a base for future projects, more specifically I'm working on the input handling. I'm using the command pattern for handling the input, when creating an input context the programmer can bind a command to a key or mouse button through an invoker that executes the command depending on the different conditions of the application, key pressed, where the mouse is on the window and so on.

I ran into trouble when I got to the part of adding handling of the mouse when in an input context where the cursor is disabled, e.g. when controlling a 3D camera (This is actually the only situation I can think of where this would be useful).

The way I see this working, is the programmer binds a command, one that rotates the camera, to be activeated once an event is created that describes mouse movement. The command would hold a pointer to the camera object and call a function like camera->pan() when executed. This command would be executed when the mouse moved in the X-Axis. However if this was the case, the camera would always pan with a constant speed, no matter how fast or slow the mouse was moved. If the cameras function pan() had a parameter for specifying how much to pan, the Command object would need to have a value for this parameter when executing. If that value is specified on creation of the command and stored as a member, the problem would arise again, since the parameter would have the same value every time the function is called.

My proposed solution to this problem is to simply create a variant of the Command class called something like WeightedCommand that had a parameter in its execute() function. This parameter would be a "weight" passed on to the cameras pan() function. This would allow for the command to be executed with a differen "weight" everytime it's called, or the same "weight", it would be up to the programmer to decide.

For reference, this is an example of the Command pattern, from wikipedia.

class Light {
 public:
  void TurnOn() { std::cout << "The light is on." << std::endl; }
  void TurnOff() { std::cout << "The light is off." << std::endl; }
};


class ICommand {
 public:
  virtual ~ICommand() = default;

  virtual void Execute() = 0;
};

// The Command for turning on the light - ConcreteCommand #1
class FlipUpCommand : public ICommand {
 public:
  FlipUpCommand(Light* light) : light_(light) { assert(light_); }

  void Execute() { light_->TurnOn(); }

 private:
  Light* light_;
};

An example of the WeightedCommand:

class WeightedCommand
{
public:
    virtual ~WeightedCommand() = default;
    virtual void execute(double weight) = 0;
};

class PanCamera : public WeightedCommand
{
public:
    PanCamer(Camera* cam)
        : _camera(cam;
    {}

    void execute(double weight)
    {
        _camera->pan(weight);
    }    
private:
    Camera* _camera;
};

Can you see any flaws with this approach. Is there a better solution already available? I tried searching for solutions to similar problems, but couldn't find anything that really fit.

Aucun commentaire:

Enregistrer un commentaire