命令模式-以“权重”执行任务的命令

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了命令模式-以“权重”执行任务的命令相关的知识,希望对你有一定的参考价值。

我目前正在为将来的项目设计基础,更具体地说,我正在进行输入处理。我使用命令模式来处理输入,当创建输入上下文时,程序员可以通过调用程序将命令绑定到按键或鼠标按钮,该调用程序根据应用程序的不同条件,按下的位置,执行命令的位置鼠标在窗口上,依此类推。

[在遇到禁用光标的输入上下文中,例如,添加鼠标处理部分时,我遇到了麻烦。当控制3D相机时(实际上这是我能想到的唯一情况)。

我看这种工作方式的方式是,程序员在创建一个描述鼠标移动的事件后,将一条命令旋转摄像机,将其绑定。该命令将持有指向相机对象的指针,并在执行时调用类似camera->pan()的函数。当鼠标在X轴中移动时,将执行此命令。但是,在这种情况下,无论鼠标移动多快或多慢,相机始终将以恒定速度平移。如果摄像机功能pan()具有用于指定平移量的参数,则执行时Command对象将需要具有该参数的值。如果在创建命令时指定了该值并将其存储为成员,则该问题将再次出现,因为每次调用该函数时该参数将具有相同的值。

我对此问题的建议解决方案是简单地创建Command类的变体,称为WeightedCommand之类的东西,该变体在execute()函数中具有参数。此参数将是传递给摄像机pan()功能的“权重”。这将允许在每次调用命令时以不同的“权重”或相同的“权重”执行命令,这取决于程序员来决定。

作为参考,这是来自维基百科的Command模式的示例。

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_;
;

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;
;

您能看到这种方法的任何缺陷吗?是否已有更好的解决方案?我曾尝试寻找解决类似问题的方法,但找不到真正合适的方法。

答案

这是一个基于意见的问题,但是这里有一些建议。

您可以保留您的方法,并通过将ICommand用作模板来进一步推广它。

template <typename ...Args>
class ICommand 

 public:
  virtual ~ICommand() = default;

  virtual void Execute(Args const& ...args) = 0;
;

class PanCamera : public ICommand<double>

    void Execute(double const& pan) override
    
        _camera->pan(pan);
        
;

如果要将命令存储在容器中,则需要一个通用类型,该类型不适用于上面的示例。为避免这种情况,您可以像已经提到的那样将double参数替换为std::variant

using CommandArgs = std::variant<double, std::string>;

class PanCamera : public ICommand<CommandArgs>

    void Execute(CommandArgs const& args) override
    
        _camera->pan(std::get<double>(args));
        
;

class SayHello : public ICommand<CommandArgs>

    void Execute(CommandArgs const& args) override
    
        display->sayHello(std::get<std::string>(args));
        
;

您也可以一起放弃ICommand界面,并将visitor pattern用作std::variant

struct PanCameraArgs

    double value = 0;
;

struct SayHelloArgs

    std::string text;
;

struct RotateCameraArgs

    double angle = 0;
;

using CommandArgs = std::variant<PanCameraArgs, SayHelloArgs, RotateCameraArgs>;

void dispatchCommand(CommandArgs const& command)

    std::visit( overloaded 
        [&] (PanCameraArgs const& args)
        
            _camera->pan(pan.value);
        
        [&] (SayHelloArgs const& args)
        
            display->sayHello(args.text);
        
        [&] (RotateCameraArgs const& args)
        
            _camera->rotate(args.angle);
        
    , command);

以上是关于命令模式-以“权重”执行任务的命令的主要内容,如果未能解决你的问题,请参考以下文章

设计模式--命令模式

从python调用命令行以使用args以批处理模式执行程序[重复]

23种设计模式之命令模式

图解“管道过滤器模式”应用实例:SOD框架的命令执行管道

CentosUbuntu开启命令模式

命令模式的理解和示例