命令模式 - 使用"weight"执行任务的命令
Command pattern - Commands that execute the task with a "weight"
我目前正在为未来的项目设计一个基础,更具体地说,我正在研究输入处理。我正在使用命令模式来处理输入,在创建输入上下文时,程序员可以通过调用程序将命令绑定到键或鼠标按钮,该调用程序根据应用程序的不同条件、按键、鼠标在窗口上的位置等执行命令。
当我在禁用光标的输入上下文中(例如在控制 3D 相机时(添加鼠标处理时,我遇到了麻烦(这实际上是我能想到的唯一情况(。
我认为这是有效的,程序员绑定一个命令,一个旋转相机的命令,一旦创建描述鼠标移动的事件就会激活。该命令将保存指向相机对象的指针,并在执行时调用类似camera->pan()
的函数。当鼠标在 X 轴上移动时,将执行此命令。但是,如果是这种情况,无论鼠标移动的速度有多快或多慢,相机都将始终以恒定的速度平移。如果相机函数pan()
具有用于指定平移量的参数,则Command
对象在执行时需要具有此参数的值。如果在创建命令时指定该值并将其存储为成员,则问题将再次出现,因为每次调用函数时,参数都将具有相同的值。
我建议的这个问题的解决方案是简单地创建Command
类的变体,称为类似WeightedCommand
的变体,其execute()
函数中有一个参数。此参数将是传递给相机pan()
功能的"权重"。这将允许每次调用命令时都以不同的"权重"执行命令,或者相同的"权重",由程序员决定。
作为参考,这是来自维基百科的命令模式的示例。
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_;
};
加权命令的示例:
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
界面,并使用访问者模式进行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);
}
- 使用QProcess执行命令,并将结果存储在QStringList中
- 如何使 windows 命令提示符在C++可执行文件上显示返回值?
- 如何创建线程序列以按照启动顺序执行任务?
- 命令模式 - 使用"weight"执行任务的命令
- 相同的CMD命令执行两种不同的事情
- 使用 UWP 中的 IAsyncOperation 继续执行任务
- std 库中是否有类/模板可以在超出范围时执行任务
- 任务管理器如何获取进程的命令行可执行路径
- 如果命令不只是打印结果,而是进入某种交互模式,如何处理来自C++的终端命令执行的输出?
- 使用linux echo命令执行qtProcess
- 与号 (&) (非常命令执行) 与 QProcess
- c++可以编写代码,将用户输入作为命令执行
- 对相关数据执行任务级并行性
- 如何用c++在Windows主循环中执行任务
- ADO命令执行失败
- 在析构函数中执行任务
- 线程在QT中执行任务时如何使用GUI
- c++程序没有使用php脚本和exec()、shell_exec()、system()等命令执行
- 如何在Windows系统中以管理员身份透明地执行任务
- 如何告诉c++并发运行时重用前一个线程来执行任务