概述

描述

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

  • 命令模式是一种对象行为型模式,其别名为动作(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 播放剧情动画

参考

【UE4 设计模式】命令模式 Command Pattern的更多相关文章

  1. 设计模式 - 命令模式(command pattern) 多命令 具体解释

    命令模式(command pattern) 多命令 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考命令模式: http://blog.csdn.ne ...

  2. 设计模式 - 命令模式(command pattern) 具体解释

    命令模式(command pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 命令模式(command pattern) : 将请求封装成对 ...

  3. 设计模式 - 命令模式(command pattern) 宏命令(macro command) 具体解释

    命令模式(command pattern) 宏命令(macro command) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考: 命名模式(撤销) ...

  4. 设计模式 - 命令模式(command pattern) 撤销(undo) 具体解释

    命令模式(command pattern) 撤销(undo) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 參考命令模式: http://blog.cs ...

  5. C#设计模式——命令模式(Command Pattern)

    一.概述通常来说,“行为请求者”与“行为实现者”是紧耦合的.但在某些场合,比如要对行为进行“记录.撤销/重做.事务”等处理,这种无法抵御变化的紧耦合是不合适的.在这些情况下,将“行为请求者”与“行为实 ...

  6. 乐在其中设计模式(C#) - 命令模式(Command Pattern)

    原文:乐在其中设计模式(C#) - 命令模式(Command Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 命令模式(Command Pattern) 作者:webabcd ...

  7. 二十四种设计模式:命令模式(Command Pattern)

    命令模式(Command Pattern) 介绍将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化:对请求排队或记录请求日志,以及支持可取消的操作. 示例有一个Message实体类,某个 ...

  8. 设计模式-15命令模式(Command Pattern)

    1.模式动机 在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计,使 ...

  9. 设计模式----行为型模式之命令模式(Command Pattern)

    下面来自head first设计模式的命令模式一章节. 定义 将"请求"封装成对象,以便使用不同的请求.队列或者日志来参数化其他对象.命令模式也支持可撤销的操作. 类图 注: 1. ...

随机推荐

  1. Spring AOP Aspect的简单实现(基于XML)

    第一步:导包 第二步:实现类和切面类 Service("userService")public class IUserviceImpl implements IUserServic ...

  2. 【曹工杂谈】Maven底层容器Plexus Container的前世今生,一代芳华终落幕

    Maven底层容器Plexus Container的前世今生,一代芳华终落幕 前言 说实话,我非常地纠结,大家平时只是用Maven,对于内部的实现其实也不关心,我现在非要拉着大家给大家讲.这就有个问题 ...

  3. JS005. 拷贝引用数据类型Array使其指向不同堆的解决方案

    一个很常见的语法问题,但专注实现需求时经常会忘记去避免,导致最终问题的出现,再花时间排查.为此专门整理一篇解决方法的博客,也加强一下自己的记忆. TAG: JSON.parse() JSON.stri ...

  4. salesforce零基础学习(一百零七)Dynamic Action

    说一下项目中常见的甲方的需求.背景如下:Order在SF端生成以后,在status为completed以后,需要点击按钮同步到SAP或者其他的MDM,客户希望的是,如果 order的状态为 compl ...

  5. Java基础之代理模式

    代理模式是常见的设计模式之一,意图在为指定对象提供一种代理以控制对这个对象的访问.Java中的代理分为动态代理和静态代理,动态代理在Java中的应用比较广泛,比如Spring的AOP实现.远程RPC调 ...

  6. EditPlus配置C/C++运行环境

    1.安装MinGW和EditPlus 2.打开EditPlus ctrl+1 编译 ctrl+2 运行

  7. composer 下载包慢

    方法一: 修改 composer 的全局配置文件(推荐方式) 打开命令行窗口(windows用户)或控制台(Linux.Mac 用户)并执行如下命令: composer config -g repo. ...

  8. TP5缩放图片加水印

    // 给图片增加水印文字 试验缩放图片,放大图片,加水印,加文字功能 public function doCreateImage1($data,$path) { $basePath = ROOT_PA ...

  9. Linux系列(3) - ls

    作用 ls:查询目录中内容 格式 ls [选项] [文件或目录] 选项 描述 -a 显示所有文件,包括隐藏文件.隐藏文件是.开头的 -l 显示详细信息:ls -l简写为ll,使用频率很高 -d 查看目 ...

  10. 对象继承深入、call_apply、圣杯模式、构造函数和闭包,企业模块化

    一个实现加减乘除的插件:   原型其实是在构造函数之上的,构造函数变成实例化函数的时候才会有原型, 原型实际上是构造函数的一个属性 原型无非就是2个字:继承 原型中继承父类所有方法是很不合理的,因为没 ...