在本教程中,我们将学习命令模式,这是一种重要的行为设计模式。 它具有一些重要的应用程序,例如在文本编辑器中实现撤消/重做功能。
在命令设计模式中,有一个命令对象位于发送方和接收方对象之间。 发送者对象可以创建命令对象。 然后,命令对象在接收器中调用暴露的方法。 因此,发送方对象不需要了解接收方及其公开的方法。
我们还有另一个称为调用程序的对象。 调用程序是负责调用适当命令对象以完成任务的对象。 我们还可以使用命令管理器来跟踪,调用和操纵命令。
为什么要使用命令设计模式?
命令模式有一些流行的用例:
- 存储和调度请求:我们可以将请求表示为命令对象,然后可以通过事件触发器将其存储在列表中,在特定时间进行操纵,排队或完成。 例如,可以通过将警报振铃表示为命令对象并在事件触发器上执行警报振铃功能来实现
- 支持完成/撤消:命令模式使我们能够执行或撤消命令执行的操作
由于每个命令对象都支持do / undo操作,因此我们可以扩展此功能以设计文本编辑器的do / undo操作。 这个想法是有两个命令对象列表– 历史记录和重做列表:
- 历史记录列表包含到目前为止已执行的所有命令
- 另一方面, 重做列表存储我们撤消的命令
- 对于每个命令请求,都会创建,执行命令对象,然后将其添加到历史记录列表中
- 在撤消请求时,我们将检查并在历史记录列表中的最新命令上调用撤消操作,然后将该命令放在重做列表中
- 对于重做操作,我们将在重做列表上执行最新的命令,再执行一次我们最近撤消的命令,然后执行该命令并将其再次移至历史记录列表
听起来很简单吧!
UML表示形式:
我们可以将命令设计模式表示为:
我们在哪里
- 命令:定义命令对象操作的接口或抽象类。
- ConcreteCommand:这些是包含特定命令实际实现的具体类
- 接收器:命令类调用接收器以执行请求的操作
- 调用者:向客户公开的类。 负责调用适当的命令
此外,每个命令类通常都提供以下方法的实现:
- execute():定义应该完成的工作
- unexecute():这是负责撤消操作的方法
- isReversible():如果可以撤消命令,则此方法应返回true ,否则返回false
示例实现:
假设我们必须为文本编辑器实现剪切复制粘贴功能。
因此,我们首先定义Command接口:
public interface Command {void execute();void unexecute();default boolean isReversible() {return true;}
}
另外,假设我们有一个支持文本插入和删除的Document类:
//class which will be our Receiver
public class Document {public void insert(String str, int position) {...}public String delete(int position, int noOfChars) {...}public void copy(int position, int noOfChars) {...}
}
编写具体命令:
现在,我们将定义CutCommand类:
public class CutCommand implements Command {private Document doc;private String text;private int startPosition;private int noOfChars;//suitable constructorpublic void execute() {this.text = this.doc.delete(startPosition, noOfChars);}public void unexecute() {this.doc.insert(text, startPosition);}
}
我们还定义其他两个命令类:
public class CopyCommand implements Command {private Document doc;private int startPosition;private int length;//suitable constructorpublic void execute() {this.doc.copy(startPosition, length);}public void unexecute() {System.out.println("Uncopy operation is blocked");}public boolean isReversible() { return false; }
}public class PasteCommand implements Command {private Document doc;private String text;private int startPosition;//suitable constructorpublic void execute() {this.doc.insert(text, startPosition);}public void unexecute() {this.doc.delete(startPosition, text.length());}
}
众所周知,取消复制不是有效的操作,我们在CopyCommand类的isReversible()方法中返回了false 。
实施调用者:
最后,我们可以编写一个调用程序类:
public class DocumentInvoker {private Document document;private CommandManager commandManager;public DocumentInvoker(Document document) {this.document = document;commandManager = CommandManage.getInstance();}public void cut(int position, int length) {Command cutCommand = new CutCommand(document, position, length);commandManager.invoke(cutCommand);}public void copy(int position, int length) {Command copyCommand = new CopyCommand(document, position, length);commandManager.invoke(copyCommand);}public void paste(String text, int position) {Command pasteCommand = new PasteCommand(document, text, position);commandManager.invoke(pasteCommand);}}
在这里, CommandManager是管理历史记录和重做列表的类。 调用程序使用所需的信息实例化命令对象,然后调用命令管理器以最终执行操作。
结论:
在本教程中,我们学习了如何在Java中实现命令设计模式。
由于发送方不需要了解任何有关接收方的信息,因此可以促进松散耦合,并且可以简单地调用操作。
翻译自: https://www.javacodegeeks.com/2019/09/command-design-pattern-in-java.html