首页 技术 正文
技术 2022年11月22日
0 收藏 924 点赞 3,419 浏览 2783 个字

概述

描述

  • 将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。

  • 命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。

  • 建造者模式将客户端与包含多个组成部分的复杂对象的创建过程分离,客户端无需知道复杂对象的内部组成与装配方式,主需要知道所需的建造者即可。类似工厂方法,但是建造者模式返回一个完整的复杂产品,而抽象工厂模式则返回一系列相关的产品。以汽车为例,工厂方法可以看成不同汽车配件的生成,而建造者模式则可以看成时汽车的组装

套路

  • 客户端 Client 

    命令的发起者。确定接下来要执行什么命令。

  • 调用者 Invoker

     命令的管理者,不关心每个命令具体是做什么内容,根据客户端的指示按序执行命令。

  • 抽象命令 Command

    命令接口协议,确定每个命令需要提供的功能,这里要求每个命令类都提供执行方法。

  • 具体命令 ConcreteCommand

    包含执行一个命令所需的所有上下文信息,例如执行接收者的哪个方法,以及方法所需要的参数,甚至命令作为GUI 显示时的相关信息,例如应该显示的图标路径。具体命令类是命令模式中的核心节点,需要重点理解。

  • 接收者 Receiver:命令所对应任务的实际执行者,位于调用链条的末端。

使用场景

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

优缺点

  • 优点

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

UE4 实践

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

  • 创建接收者抽象类、具体类 —— 场景传送、触发剧情

    • 此处抽象类非必要,但实际使用可能会有多个派生类多种 action 成员函数被使用
    // 抽象接收者类 Receiver
    UCLASS()
    class DESIGNPATTERNS_API UCmdReceiver : public UObject
    {
    GENERATED_BODY()
    public:virtual void Action() { check(0 && "You must override this"); }
    };// 具体接收者类 Receiver —— 场景传送
    UCLASS()
    class DESIGNPATTERNS_API ULevelPortal : public UCmdReceiver
    {
    GENERATED_BODY()
    public:
    virtual void Action() override {
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" 传送到下一个场景"));
    }
    };// 具体接收者类 Receiver —— 资料片播放
    UCLASS()
    class DESIGNPATTERNS_API UCutscene : public UCmdReceiver
    {
    GENERATED_BODY()
    public:
    virtual void Action() override {
    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" 播放剧情动画"));
    }
    };
  • 抽象命令类、具体命令类 —— 场景传送命令、资料片播放命令

    • 此处 接收者 采用了继承方式,因此和具体命令搭起来,代码显得重复。实际使用时,Execute成员函数可能会重载,调用不同类对象进行处理
    // 抽象命令类
    UCLASS(Abstract)
    class DESIGNPATTERNS_API UCommand : public UObject
    {
    GENERATED_BODY()
    public:void SetReceiver(UCmdReceiver* pCmdReceiver) { m_pCmdReceiver = pCmdReceiver; }// 调用接收者的 Action
    virtual void Execute() {
    if (m_pCmdReceiver)
    {
    m_pCmdReceiver->Action();
    }
    }
    // virtual void undo()protected:
    UCmdReceiver *m_pCmdReceiver;
    };// 具体命令类 —— 场景传送命令
    UCLASS()
    class DESIGNPATTERNS_API UPortalCommand : public UCommand
    {
    GENERATED_BODY()
    public:// 可重载做些额外的工作
    //virtual void Execute() override { }
    };// 具体命令类 —— 资料片播放命令
    UCLASS()
    class DESIGNPATTERNS_API UCutsceneCommand : public UCommand
    {
    GENERATED_BODY()
    public:// 可重载做些额外的工作
    //virtual void Execute() override { }
    };
  • 调用者 Invoker

    UCLASS()
    class DESIGNPATTERNS_API ACommandActor : public AActor
    {
    GENERATED_BODY()
    public:void BeginPlay() override {// 创建接收者 场景传送
    ULevelPortal* LevelPortal = NewObject<ULevelPortal>();// 创建命令对象
    UPortalCommand* PortalCommand = NewObject<UPortalCommand>();
    PortalCommand->SetReceiver(LevelPortal);// this 当做调用者 Invoker
    PortalCommand->Execute();// 创建接收者 资料片播放
    UCutscene* Cutscene = NewObject<UCutscene>();// 创建命令对象
    UCutsceneCommand* CutsceneCommand = NewObject<UCutsceneCommand>();
    CutsceneCommand->SetReceiver(Cutscene);// this 当做调用者 Invoker
    CutsceneCommand->Execute();
    }
    };
  • 调式输出

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

参考

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,104
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,580
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,428
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,200
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,835
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,918