• UE4 C++设计模式:命令模式(Command Pattern)


    目录

    描述

    套路

    使用场景

    优缺点

    UE4实践

    创建抽象接受者类CmdReceiver

    创建具体接受者类:LevelPortal

    创建具体接受者类:Cutscene

    抽象命令类:Command

    具体命令类:场景传送命令

    具体命令类:资料片播放命令

    调用者Invoker


    描述

    • 将一个请求封装为一个对象,从而使我们可用不同请求对客户进行参数化;对请求排队或者记录请求状态,以及支持可撤销的操作
    • 命令模式是一种行为型模式,其别名为动作(Action)模式或者事物(Transaction)模式
    • 软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计,使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活。

      命令模式可以对发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。这就是命令模式的模式动机

    套路

    • 客户端Client
      • 命令的发起者,确定接下来要执行什么命令
    • 调用者Invoker
      • 命令的管理者,不关心每个命令具体做什么内容,根据客户端的指示按序执行命令
    • 抽象命令Command
      • 命令接口协议,确定每个命令需要提供的功能,这里要求每个命令类都提供执行方法
    • 具体命令ConcreteCommand
      • 包含执行一个命令所需的所有上下文信息,例如执行接受者的哪个方法,以及方法所需要的参数,甚至命令作为GUI显示时的相关信息,例如应该显示的图标路径
      • 具体命令是命令模式中的核心节点
    • 接受者Receiver
      • 命令所对应任务的实际执行者,位于调用链条末端

    使用场景

    • 系统需要将请求调用者和请求接受者解耦,使得调用者和接受者不直接交互
    • 系统需要在不同的时间指定请求,将请求排队和执行请求
    • 系统需要将一组操作组合在一起,即支持宏命令
    • 示例
      • 按键、快捷键映射、玩家输入
      • 撤销、欧服、维护命令列表
      • 新手引导

    优缺点

    • 优点
      • 降低系统耦合度
      • 新的命令可以很容易的加入到系统中
      • 可以比较容易的设计一个命令队列和宏命令
      • 可以方便的实现对请求的Undo和Redo
    • 缺点
      • 使用命令模式可能导致某些系统有过多的具体命令类,因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用

    UE4实践

    一个事件触发器,点击地图地点触发场景传送;点击资料片播放过场动画

    创建抽象接受者类CmdReceiver

    1. // 抽象接收者类 Receiver
    2. UCLASS()
    3. class DESIGNPATTERNS_API UCmdReceiver : public UObject
    4. {
    5. GENERATED_BODY()
    6. public:
    7. virtual void Action() { check(0 && "You must override this"); }
    8. };

    创建具体接受者类:LevelPortal

    1. // 具体接收者类 Receiver —— 场景传送
    2. UCLASS()
    3. class DESIGNPATTERNS_API ULevelPortal : public UCmdReceiver
    4. {
    5. GENERATED_BODY()
    6. public:
    7. virtual void Action() override {
    8. UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" 传送到下一个场景"));
    9. }
    10. };

    创建具体接受者类:Cutscene

    1. // 具体接收者类 Receiver —— 资料片播放
    2. UCLASS()
    3. class DESIGNPATTERNS_API UCutscene : public UCmdReceiver
    4. {
    5. GENERATED_BODY()
    6. public:
    7. virtual void Action() override {
    8. UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" 播放剧情动画"));
    9. }
    10. };

    抽象命令类:Command

    1. // 抽象命令类
    2. UCLASS(Abstract)
    3. class DESIGNPATTERNS_API UCommand : public UObject
    4. {
    5. GENERATED_BODY()
    6. public:
    7. void SetReceiver(UCmdReceiver* pCmdReceiver) { m_pCmdReceiver = pCmdReceiver; }
    8. // 调用接收者的 Action
    9. virtual void Execute() {
    10. if (m_pCmdReceiver)
    11. {
    12. m_pCmdReceiver->Action();
    13. }
    14. }
    15. // virtual void undo()
    16. protected:
    17. UCmdReceiver *m_pCmdReceiver;
    18. };

    具体命令类:场景传送命令

    1. // 具体命令类 —— 场景传送命令
    2. UCLASS()
    3. class DESIGNPATTERNS_API UPortalCommand : public UCommand
    4. {
    5. GENERATED_BODY()
    6. public:
    7. // 可重载做些额外的工作
    8. //virtual void Execute() override { }
    9. };

    具体命令类:资料片播放命令

    1. // 具体命令类 —— 资料片播放命令
    2. UCLASS()
    3. class DESIGNPATTERNS_API UCutsceneCommand : public UCommand
    4. {
    5. GENERATED_BODY()
    6. public:
    7. // 可重载做些额外的工作
    8. //virtual void Execute() override { }
    9. };

    调用者Invoker

    1. UCLASS()
    2. class DESIGNPATTERNS_API ACommandActor : public AActor
    3. {
    4. GENERATED_BODY()
    5. public:
    6. void BeginPlay() override {
    7. // 创建接收者 场景传送
    8. ULevelPortal* LevelPortal = NewObject();
    9. // 创建命令对象
    10. UPortalCommand* PortalCommand = NewObject();
    11. PortalCommand->SetReceiver(LevelPortal);
    12. // this 当做调用者 Invoker
    13. PortalCommand->Execute();
    14. // 创建接收者 资料片播放
    15. UCutscene* Cutscene = NewObject();
    16. // 创建命令对象
    17. UCutsceneCommand* CutsceneCommand = NewObject();
    18. CutsceneCommand->SetReceiver(Cutscene);
    19. // this 当做调用者 Invoker
    20. CutsceneCommand->Execute();
    21. }
    22. };

    LogTemp: Warning: ULevelPortal::Action 传送到下一个场景
    LogTemp: Warning: UCutscene::Action 播放剧情动画
     

  • 相关阅读:
    深入了解Vue.js框架:构建现代化的用户界面
    Latex学习(1)——latex中的字体颜色
    在列表中按照概率抽样choice()
    Linux从入门到精通(八)——Linux磁盘管理
    Cisco switch常用命令
    【Nginx】Nginx实现图片防盗链
    AtCoder ABC132
    你好,法语!A2知识点总结(2)
    GBase 8c产品简介
    windows service 服务器安装 MySQL
  • 原文地址:https://blog.csdn.net/Jason6620/article/details/126541565