[设计模式] 设计模式课程(二十)--命令模式(Command)
概述
- “行为变化”模式:组件构建过程中,组件行为的变化经常会导致组件本身剧烈的变化。“行为变化”模式将组件的行为和组件本身进行解耦,从而支持组件行为的变化,实现两者之间的松耦合
- 动机:在软件构建过程中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合——如需要对行为进行“记录、撤销(redo/undo)”等处理,这种无法抵御变化的紧耦合是不合适的
- 如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,可实现二者间的松耦合
- GoF:一个请求(行为)封装为对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,及支持可撤销的操作
- 封装:创建对象的过程
- 对象能干什么:当做参数传递,当做字段存储,序列化,存在数据结构里(灵活性)
- Command模式的根本目的在于将“行为请求者”与“行为实现者”解耦,在面向对象语言中,常见的实现手段是“将行为抽象为对象”
- 实现Command接口的具体命令对象ConcreteCommand有时根据需要可能会保存一些额外的信息,通过使用Composite模式,可能将多个“命令”封装为一个“复合命令”MacroCommand
- Command模式与C++中的函数对象有些类似(都实现了行为对象化),但两者定义行为接口的规范有所区别:Command以面向对象中的“接口-实现”来定义行为接口规范,更严格,但有性能损失(运行时绑定);C++函数对象以函数签名来定义行为接口规范,更灵活,性能更高(编译时绑定)
- C++中一般用函数对象+泛型编程替代(性能高),在 Java, C#, Swift 中应用广泛
- 一种观点:设计模式是弥补语言模式的不足而出现

场景
- 餐厅点菜,通过服务员把点菜单传递给厨师做菜
- GUI中,通过菜单,工具栏,快捷键等实现复制功能
- 通过操作来参数化对象
- 将操作放入队列中,远程执行操作
- 实现操作回滚功能
结构

- 发送者(触发者)类:对请求进行初始化,包含成员变量存储对命令对象的引用
- 命令接口:声明一个执行命令的方法
- 具体命令:实现各种类型的请求
- 接收者:包含业务逻辑
- 客户端:创建并配置
场景
示例1
Command.cpp

1 #include <iostream>
2 #include <vector>
3 #include <string>
4 using namespace std;
5
6 class Command
7 {
8 public:
9 virtual void execute() = 0;
10 };
11
12 class ConcreteCommand1 : public Command
13 {
14 string arg;
15 public:
16 ConcreteCommand1(const string & a) : arg(a) {}
17 void execute() override
18 {
19 cout<< "#1 process..."<<arg<<endl;
20 }
21 };
22
23 class ConcreteCommand2 : public Command
24 {
25 string arg;
26 public:
27 ConcreteCommand2(const string & a) : arg(a) {}
28 void execute() override
29 {
30 cout<< "#2 process..."<<arg<<endl;
31 }
32 };
33
34 class MacroCommand : public Command
35 {
36 vector<Command*> commands;
37 public:
38 void addCommand(Command *c) { commands.push_back(c); }
39 void execute() override
40 {
41 for (auto &c : commands)
42 {
43 c->execute();
44 }
45 }
46 };
47
48 int main()
49 {
50
51 ConcreteCommand1 command1(receiver, "Arg ###");
52 ConcreteCommand2 command2(receiver, "Arg $$$");
53
54 MacroCommand macro;
55 macro.addCommand(&command1);
56 macro.addCommand(&command2);
57
58 macro.execute();
59
60 }
- 43:运行时辨析,c的具体类型决定excute()操作是什么
- 51-52:创建命令
- 54-56:组合命令
- 58:执行命令
示例2


1 // 命令基类会为所有具体命令定义通用接口。
2 abstract class Command is
3 protected field app: Application
4 protected field editor: Editor
5 protected field backup: text
6
7 constructor Command(app: Application, editor: Editor) is
8 this.app = app
9 this.editor = editor
10
11 // 备份编辑器状态。
12 method saveBackup() is
13 backup = editor.text
14
15 // 恢复编辑器状态。
16 method undo() is
17 editor.text = backup
18
19 // 执行方法被声明为抽象以强制所有具体命令提供自己的实现。该方法必须根
20 // 据命令是否更改编辑器的状态返回 true 或 false。
21 abstract method execute()
22
23
24 // 这里是具体命令。
25 class CopyCommand extends Command is
26 // 复制命令不会被保存到历史记录中,因为它没有改变编辑器的状态。
27 method execute() is
28 app.clipboard = editor.getSelection()
29 return false
30
31 class CutCommand extends Command is
32 // 剪切命令改变了编辑器的状态,因此它必须被保存到历史记录中。只要方法
33 // 返回 true,它就会被保存。
34 method execute() is
35 saveBackup()
36 app.clipboard = editor.getSelection()
37 editor.deleteSelection()
38 return true
39
40 class PasteCommand extends Command is
41 method execute() is
42 saveBackup()
43 editor.replaceSelection(app.clipboard)
44 return true
45
46 // 撤销操作也是一个命令。
47 class UndoCommand extends Command is
48 method execute() is
49 app.undo()
50 return false
51
52
53 // 全局命令历史记录就是一个堆桟。
54 class CommandHistory is
55 private field history: array of Command
56
57 // 后进...
58 method push(c: Command) is
59 // 将命令压入历史记录数组的末尾。
60
61 // ...先出
62 method pop():Command is
63 // 从历史记录中取出最近的命令。
64
65
66 // 编辑器类包含实际的文本编辑操作。它会担任接收者的角色:最后所有命令都会
67 // 将执行工作委派给编辑器的方法。
68 class Editor is
69 field text: string
70
71 method getSelection() is
72 // 返回选中的文字。
73
74 method deleteSelection() is
75 // 删除选中的文字。
76
77 method replaceSelection(text) is
78 // 在当前位置插入剪贴板中的内容。
79
80 // 应用程序类会设置对象之间的关系。它会担任发送者的角色:当需要完成某些工
81 // 作时,它会创建并执行一个命令对象。
82 class Application is
83 field clipboard: string
84 field editors: array of Editors
85 field activeEditor: Editor
86 field history: CommandHistory
87
88 // 将命令分派给 UI 对象的代码可能会是这样的。
89 method createUI() is
90 // ...
91 copy = function() { executeCommand(
92 new CopyCommand(this, activeEditor)) }
93 copyButton.setCommand(copy)
94 shortcuts.onKeyPress("Ctrl+C", copy)
95
96 cut = function() { executeCommand(
97 new CutCommand(this, activeEditor)) }
98 cutButton.setCommand(cut)
99 shortcuts.onKeyPress("Ctrl+X", cut)
100
101 paste = function() { executeCommand(
102 new PasteCommand(this, activeEditor)) }
103 pasteButton.setCommand(paste)
104 shortcuts.onKeyPress("Ctrl+V", paste)
105
106 undo = function() { executeCommand(
107 new UndoCommand(this, activeEditor)) }
108 undoButton.setCommand(undo)
109 shortcuts.onKeyPress("Ctrl+Z", undo)
110
111 // 执行一个命令并检查它是否需要被添加到历史记录中。
112 method executeCommand(command) is
113 if (command.execute)
114 history.push(command)
115
116 // 从历史记录中取出最近的命令并运行其 undo(撤销)方法。请注意,你并
117 // 不知晓该命令所属的类。但是我们不需要知晓,因为命令自己知道如何撤销
118 // 其动作。
119 method undo() is
120 command = history.pop()
121 if (command != null)
122 command.undo()
参考
https://refactoringguru.cn/design-patterns/command
[设计模式] 设计模式课程(二十)--命令模式(Command)的更多相关文章
- 二十四种设计模式:命令模式(Command Pattern)
命令模式(Command Pattern) 介绍将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化:对请求排队或记录请求日志,以及支持可取消的操作. 示例有一个Message实体类,某个 ...
- Java 设计模式系列(十四)命令模式(Command)
Java 设计模式系列(十四)命令模式(Command) 命令模式把一个请求或者操作封装到一个对象中.命令模式允许系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复 ...
- 命令模式 Command 行为型 设计模式(十八)
命令模式(Command) 请分析上图中这条命令的涉及到的角色以及执行过程,一种可能的理解方式是这样子的: 涉及角色为:大狗子和大狗子他妈 过程为:大狗子他妈角色 调用 大狗子的“回家吃饭”方法 引子 ...
- 设计模式 ( 二十 ) 访问者模式Visitor(对象行为型)
设计模式 ( 二十 ) 访问者模式Visitor(对象行为型) 1.概述 在软件开发过程中,对于系统中的某些对象,它们存储在同一个集合collection中,且具有不同的类型,而且对于该集合中的对象, ...
- 设计模式 ( 十三 ) 命令模式Command(对象行为型)
设计模式 ( 十三 ) 命令模式Command(对象行为型) 1.概述 在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需 ...
- 乐在其中设计模式(C#) - 命令模式(Command Pattern)
原文:乐在其中设计模式(C#) - 命令模式(Command Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 命令模式(Command Pattern) 作者:webabcd ...
- Java 设计模式系列(二十)状态模式
Java 设计模式系列(二十)状态模式 状态模式,又称状态对象模式(Pattern of Objects for States),状态模式是对象的行为模式.状态模式允许一个对象在其内部状态改变的时候改 ...
- C#设计模式——命令模式(Command Pattern)
一.概述通常来说,“行为请求者”与“行为实现者”是紧耦合的.但在某些场合,比如要对行为进行“记录.撤销/重做.事务”等处理,这种无法抵御变化的紧耦合是不合适的.在这些情况下,将“行为请求者”与“行为实 ...
- 设计模式 - 命令模式(command pattern) 多命令 具体解释
命令模式(command pattern) 多命令 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考命令模式: http://blog.csdn.ne ...
- 设计模式 - 命令模式(command pattern) 具体解释
命令模式(command pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 命令模式(command pattern) : 将请求封装成对 ...
随机推荐
- Android Studio 之 编写精美的聊天界面
•准备工作 首先制作一张 .9 格式的聊天气泡,参见我的这篇博客: 需要注意的是,制作完成后,应该将原始文件删除,否则AS会分不清楚而报错. 新建一个 Empty Activity,Java 和 XM ...
- vue 快速入门 系列 —— 侦测数据的变化 - [vue 源码分析]
其他章节请看: vue 快速入门 系列 侦测数据的变化 - [vue 源码分析] 本文将 vue 中与数据侦测相关的源码摘了出来,配合上文(侦测数据的变化 - [基本实现]) 一起来分析一下 vue ...
- 2021 小白版,360 行行行转 IT
hey guys ,我是 cxuan,这一篇文章我就要和你聊聊编程如何学习,这一篇文章涉及的内容简直太多了,我将从入门开始,一步一步到如何提高,然后到一些学习的相关问题,还有一些计算机相关的术语等,干 ...
- lms框架分布式事务使用简介
lms框架的分布式事务解决方案采用的TCC事务模型.在开发过程中参考和借鉴了hmily.使用AOP的编程思想,在rpc通信过程中通过拦截器的方式对全局事务或是分支事务进行管理和协调. 本文通过lms. ...
- 201871030116-李小龙 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告
项目 内容 课程班级博客链接 https://edu.cnblogs.com/campus/xbsf/2018CST 这个作业要求链接 https://www.cnblogs.com/nwnu-dai ...
- 201871030140-朱婷婷 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告
项目 内容 课程班级博客链接 2018级卓越班 这个作业要求链接 实验三 结对项目 我的课程学习目标 1.体验软件项目开发中的两人合作,练习结对编程:2.掌握GitHub协作开发程序的操作方法. 这个 ...
- 【CTF】XCTF Misc 心仪的公司 & 就在其中 writeup
前言 这两题都是Misc中数据包的题目,一直觉得对数据包比较陌生,不知道怎么处理. 这里放两道题的wp,第一题strings命令秒杀觉得非常优秀,另外一题有涉及RSA加密与解密(本文不具体讨论RSA非 ...
- 在Win10中手动添加/修改本地IP
1 前言 好久没动Win10了... 今天需要用Win10做一下实验,手动修改IP,于是写下了这篇文章作为过程记录. 2 概述 Win10里面修改本地IP不是一件特别困难的事,简单来说可以分为两种方式 ...
- Linux下屏幕亮度的调节
1 概述 Linux下的屏幕调节可以通过图形界面或者命令行进行调节,图形界面的话主要就是在设置中进行调节,如果设置中没有相应的选项可以进行手动调节. 2 手动调节 2.1 手动屏幕调节 亮度由ACPI ...
- Spring/SpringBoot整合QuartZ
https://www.bilibili.com/video/av55637917/?p=2