1. 意图
将请求转换为一个包含与请求相关的所有信息的独立对象。该转换让你能根据不同的请求将方法参数化、延迟请求执行或将其放入队列中,且能实现可撤销操作
2. 动机
假如开发一款新的文字编辑器,当前的任务是创建一个包含多个按钮的工具栏,并让每个按钮对应编辑器的不同操作。创建了一个非常简洁的按钮
类,它不仅可用于生成工具栏上的按钮,还可用于生成各种对话框的通用按钮。尽管所有按钮看上去都很相似, 但它们可以完成不同的操作 (打开、 保存、 打印和应用等)。 问题是在哪里放置这些按钮的点击处理代码呢? 最简单的解决方案是在使用按钮的每个地方都创建大量的子类。 这些子类中包含按钮点击后必须执行的代码。
但是这种方式有严重的缺陷。首先,创建了大量的子类,当每次修改基类按钮时,都有可能需要修改所有子类的代码。简单来说,GUI 代码以一种拙劣的方式依赖于业务逻辑中的不稳定代码(违背了依赖倒置原则)。更棘手的是,复制/粘贴文字等操作可能会在多个地方被调用。例如用户可以点击工具栏上小小的 "复制" 按钮,或者通过上下文菜单复制一些内容,又或者直接使用键盘上的 Ctrl+C
。我们的程序最初只有工具栏,因此可以使用按钮子类来实现各种不同操作。换句话来说,复制按钮
CopyButton子类包含复制文字的代码是可行的。在实现了上下文菜单、快捷方式和其他功能后,要么需要将操作代码复制进许多个类中,要么需要让菜单依赖于按钮,而后者是更糟糕的选择
优秀的软件设计通常会将变化的部分进行封装,而这往往会导致软件的分层。最常见的例子:一层负责用户图像界面;另一层负责业务逻辑。GUI 层负责在屏幕上渲染美观的图形,捕获所有输入并显示用户和程序工作的结果。当需要完成一些重要内容时(比如计算月球轨道或撰写年度报告),GUI 层则会将工作委派给业务逻辑底层。在代码中就是,一个 GUI 对象传递一些参数来调用一个业务逻辑对象。这个过程通常被描述为一个对象发送请求给另一个对象。
命令模式建议 GUI 对象不直接提交这些请求。 应该将请求的所有细节 (例如调用的对象、 方法名称和参数列表) 抽取出来组成命令类, 该类中仅包含一个用于触发请求的方法。GUI 对象触发命令即可,命令对象会自行处理所有细节工作。所有命令实现相同的接口。该接口通常只有一个没有任何参数的执行方法,让你能在不和具体命令类耦合的情况下使用同一请求发送者执行不同命令。此外还有额外的好处,现在你能在运行时切换连接至发送者的命令对象,以此改变发送者的行为。
3. 适用性
- 如果需要通过操作来参数化对象,可以使用命令模式
命令模式可将特定的方法调用转化为独立对象。故而可以将命令作为方法的参数进行传递、将命令保存在其他对象中,或者在运行时切换已连接的命令等。
- 如果想要将操作放入队列中或者远程执行操作,可使用命令模式
同其他对象一样,命令也可以实现序列化(序列化的意思是转化为字符串),从而能方便地写入文件或数据库中。一段时间后,该字符串可被恢复成为最初的命令对象。因此,你可以延迟或计划命令的执行。但其功能远不止如此!使用同样的方式,你还可以将命令放入队列、记录命令或者通过网络发送命令
- 如果你想要实现操作回滚功能, 可使用命令模式
尽管有很多方法可以实现撤销和恢复功能,但命令模式可能是其中最常用的一种。为了能够回滚操作,你需要实现已执行操作的历史记录功能。命令历史记录是一种包含所有已执行命令对象及其相关程序状态备份的栈结构。这种方法有两个缺点:
首先,程序状态的保存功能并不容易实现,因为部分状态可能是私有的。你可以使用备忘录模式来在一定程度上解决这个问题。
其次,备份状态可能会占用大量内存。因此,有时你需要借助另一种实现方式:命令无需恢复原始状态,而是执行反向操作。反向操作也有代价:它可能会很难甚至是无法实现
- 支持修改日志,这样在系统崩溃时,修改可以被重做一遍。在command接口中添加装载操作和存储操作,可以用来保持一个一致的修改日志。从崩溃中恢复的过程包括从磁盘中重新读入记录下的命令并用Execute操作重新执行它们
- 用构建在原语操作上的高层操作构建一个系统。这样一种结构在支持事物的信息系统中很常见。一个事务封装了对数据的一组变动。Command模式提供了对事务进行建模的方法。Command有一个公共接口,使得你可以用同一种方式调用所有的事务。同时,使用该模式也易于添加新事务以扩展系统
4. 结构
5. 效果
1. Command模式将调用操作的对象与知道如何实现该操作的对象解耦(单一职责原则)
2. 实现撤销和恢复功能
3. 实现操作的延迟执行
4. 可以将多个命令装配成一个组合命令。一般来说,组合命令是Composite模式的一个实例
5. 可以在不修改客户端代码的情况下,在程序中创建新的命令(开闭原则)
6. 代码实现
commands/Command.java: 抽象基础命令
package command.commands;import command.editor.Editor;/** * @author GaoMing * @date 2021/7/25 - 20:05 */public abstract class Command { public Editor editor; private String backup; Command(Editor editor) { this.editor = editor; } void backup() { backup = editor.textField.getText(); } public void undo() { editor.textField.setText(backup); } public abstract boolean execute();}
commands/CopyCommand.java: 将所选文字复制到剪贴板
package command.commands;import command.editor.Editor;/** * @author GaoMing * @date 2021/7/25 - 20:06 */public class CopyCommand extends Command { public CopyCommand(Editor editor) { super(editor); } @Override public boolean execute() { editor.clipboard = editor.textField.getSelectedText(); return false; }}
commands/PasteCommand.java: 从剪贴板粘贴文字
package command.commands;import command.editor.Editor;/** * @author GaoMing * @date 2021/7/25 - 20:06 */public class PasteCommand extends Command{ public PasteCommand(Editor editor) { super(editor); } @Override public boolean execute() { if (editor.clipboard == null || editor.clipboard.isEmpty()) return false; backup(); editor.textField.insert(editor.clipboard, editor.textField.getCaretPosition()); return true; }}
commands/CutCommand.java: 将文字剪切到剪贴板
package command.commands;import command.editor.Editor;/** * @author GaoMing * @date 2021/7/25 - 20:06 */public class CutCommand extends Command{ public CutCommand(Editor editor) { super(editor); } @Override public boolean execute() { if (editor.textField.getSelectedText().isEmpty()) return false; backup(); String source = editor.textField.getText(); editor.clipboard = editor.textField.getSelectedText(); editor.textField.setText(cutString(source)); return true; } private String cutString(String source) { String start = source.substring(0, editor.textField.getSelectionStart()); String end = source.substring(editor.textField.getSelectionEnd()); return start + end; }}
commands/CommandHistory.java: 命令历史
package command.commands;import java.util.Stack;/** * @author GaoMing * @date 2021/7/25 - 20:06 */public class CommandHistory { private Stack<Command> history = new Stack<>(); public void push(Command c) { history.push(c); } public Command pop() { return history.pop(); } public boolean isEmpty() { return history.isEmpty(); }}
editor/Editor.java: 文字编辑器的 GUI
package command.editor;import command.commands.*;import javax.swing.*;import java.awt.*;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;/** * @author GaoMing * @date 2021/7/25 - 20:06 */public class Editor { public JTextArea textField; public String clipboard; private CommandHistory history = new CommandHistory(); public void init() { JFrame frame = new JFrame("Text editor (type & use buttons, Luke!)"); JPanel content = new JPanel(); frame.setContentPane(content); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS)); textField = new JTextArea(); textField.setLineWrap(true); content.add(textField); JPanel buttons = new JPanel(new FlowLayout(FlowLayout.CENTER)); JButton ctrlC = new JButton("Ctrl+C"); JButton ctrlX = new JButton("Ctrl+X"); JButton ctrlV = new JButton("Ctrl+V"); JButton ctrlZ = new JButton("Ctrl+Z"); Editor editor = this; ctrlC.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { executeCommand(new CopyCommand(editor)); } }); ctrlX.addActionListener(new ActionListener() {......原文转载:http://www.shaoqun.com/a/892284.html
跨境电商:https://www.ikjzd.com/
韩蓬:https://www.ikjzd.com/w/1635
新蛋:https://www.ikjzd.com/w/79
olive:https://www.ikjzd.com/w/2025
1.意图 将请求转换为一个包含与请求相关的所有信息的独立对象。该转换让你能根据不同的请求将方法参数化、延迟请求执行或将其放入队列中,且能实现可撤销操作 2.动机 假如开发一款新的文字编辑器,当前的任务是创建一个包含多个按钮的工具栏,并让每个按钮对应编辑器的不同操作。创建了一个非常简洁的按钮类,它不仅可用于生成工具栏上的按钮,还可用于生成各种对话框的通用按钮。尽管所有按钮看上去都很相似,但它们
四川汶川多地泥石流灾害 2人失联3人被困:http://www.30bags.com/a/424909.html
四川卧龙暴雨引发泥石流 12400名旅客被疏散:http://www.30bags.com/a/424927.html
四川卧龙暴雨致96人被困 当地疏散游客近11000人:http://www.30bags.com/a/425287.html
四川五一旅游景点推荐 :http://www.30bags.com/a/412760.html
他扒开我的下面舌头伸进去 吃她两腿中间的小豆豆:http://lady.shaoqun.com/a/247454.html
啊学长别揉了都出水了 揉她两腿中间的小豆豆:http://lady.shaoqun.com/m/a/247352.html
口述小姑两瓣湿乎乎:和姑姑发生了不该发生的关系:http://www.30bags.com/m/a/249622.html
老师张开腿让你桶个够 昏暗公车被直接进入:http://www.30bags.com/m/a/249959.html
深圳宝安科技馆8月展览汇总(持续更新):http://www.30bags.com/a/517601.html
2021时尚深圳展蝶讯馆展览好看吗:http://www.30bags.com/a/517602.html
2021时尚深圳蝶讯馆观展攻略:http://www.30bags.com/a/517603.html
深圳欢乐谷夏浪音乐节有朱星杰吗:http://www.30bags.com/a/517604.html
No comments:
Post a Comment