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