指挥模式是行为设计模式的一种。命令设计模式用于在请求-响应模型中实现松耦合 。
命令模式
在命令模式中,请求被发送到
invoker
,调用者将其传递给封装的Command
对象。命令对象将请求传递给Receiver
的相应方法,以执行具体的操作。客户端程序创建接收器对象,然后将其附加到命令。然后,它创建调用者对象并附加命令对象以执行操作。现在,当客户端程序执行该操作时,它将根据命令和接收器对象进行处理。
命令设计模式示例
我们将查看一个可以实现命令模式的真实场景。假设我们想要提供一个文件系统实用程序,其中包含打开、写入和关闭文件的方法。该文件系统实用程序应支持多种操作系统,如Windows和Unix。要实现我们的文件系统实用程序,首先需要创建实际执行所有工作的Receiver类。由于我们按照Java中的接口进行编码,所以我们可以拥有FileSystemReceiver
接口及其针对Windows、Unix、Solaris等不同操作系统风格的实现类。
命令模式接收器类
1package com.journaldev.design.command;
2
3public interface FileSystemReceiver {
4
5 void openFile();
6 void writeFile();
7 void closeFile();
8}
FileSystemReceiver接口定义了实现类的约定。为简单起见,我创建了两种风格的Receiver类来处理Unix和Windows系统。
1package com.journaldev.design.command;
2
3public class UnixFileSystemReceiver implements FileSystemReceiver {
4
5 @Override
6 public void openFile() {
7 System.out.println("Opening file in unix OS");
8 }
9
10 @Override
11 public void writeFile() {
12 System.out.println("Writing file in unix OS");
13 }
14
15 @Override
16 public void closeFile() {
17 System.out.println("Closing file in unix OS");
18 }
19
20}
1package com.journaldev.design.command;
2
3public class WindowsFileSystemReceiver implements FileSystemReceiver {
4
5 @Override
6 public void openFile() {
7 System.out.println("Opening file in Windows OS");
8
9 }
10
11 @Override
12 public void writeFile() {
13 System.out.println("Writing file in Windows OS");
14 }
15
16 @Override
17 public void closeFile() {
18 System.out.println("Closing file in Windows OS");
19 }
20
21}
您注意到覆盖注释了吗?如果您想知道为什么要使用它,请阅读Java annotations和Override Annotation benefits。既然我们的Receiver类已经准备好了,我们可以开始实现我们的Command类了。
命令模式接口及其实现
我们可以使用[接口或抽象class](/community/tutorials/difference-between-abstract-class-and-interface-in-javaJava中抽象类和接口的区别
来创建我们的基本命令,这是一个设计决策,取决于您的需求。我们使用接口,因为我们没有任何默认实现。
1package com.journaldev.design.command;
2
3public interface Command {
4
5 void execute();
6}
现在,我们需要为接收方执行的所有不同类型的操作创建实现。因为我们有三个操作,所以我们将创建三个Command实现。每个命令实现都会将请求转发给相应的接收方方法。
1package com.journaldev.design.command;
2
3public class OpenFileCommand implements Command {
4
5 private FileSystemReceiver fileSystem;
6
7 public OpenFileCommand(FileSystemReceiver fs){
8 this.fileSystem=fs;
9 }
10 @Override
11 public void execute() {
12 //open command is forwarding request to openFile method
13 this.fileSystem.openFile();
14 }
15
16}
1package com.journaldev.design.command;
2
3public class CloseFileCommand implements Command {
4
5 private FileSystemReceiver fileSystem;
6
7 public CloseFileCommand(FileSystemReceiver fs){
8 this.fileSystem=fs;
9 }
10 @Override
11 public void execute() {
12 this.fileSystem.closeFile();
13 }
14
15}
1package com.journaldev.design.command;
2
3public class WriteFileCommand implements Command {
4
5 private FileSystemReceiver fileSystem;
6
7 public WriteFileCommand(FileSystemReceiver fs){
8 this.fileSystem=fs;
9 }
10 @Override
11 public void execute() {
12 this.fileSystem.writeFile();
13 }
14
15}
现在我们已经准备好接收器和命令实现,所以我们可以开始实现Invoker类了。
命令模式编译器类
Invoker是一个简单的类,它封装了Command,并将请求传递给命令对象进行处理。
1package com.journaldev.design.command;
2
3public class FileInvoker {
4
5 public Command command;
6
7 public FileInvoker(Command c){
8 this.command=c;
9 }
10
11 public void execute(){
12 this.command.execute();
13 }
14}
我们的文件系统实用程序实现已经准备好了,我们可以编写一个简单的命令模式客户端程序了。但在此之前,我将提供一个实用程序方法来创建适当的FileSystemReceiver
对象。因为我们可以使用System类来获取操作系统information,,所以我们将使用它,否则我们可以使用Factory pattern来根据输入返回适当的类型。
1package com.journaldev.design.command;
2
3public class FileSystemReceiverUtil {
4
5 public static FileSystemReceiver getUnderlyingFileSystem(){
6 String osName = System.getProperty("os.name");
7 System.out.println("Underlying OS is:"+osName);
8 if(osName.contains("Windows")){
9 return new WindowsFileSystemReceiver();
10 }else{
11 return new UnixFileSystemReceiver();
12 }
13 }
14
15}
现在让我们来创建命令模式示例客户端程序,该程序将使用我们的文件系统实用程序。
1package com.journaldev.design.command;
2
3public class FileSystemClient {
4
5 public static void main(String[] args) {
6 //Creating the receiver object
7 FileSystemReceiver fs = FileSystemReceiverUtil.getUnderlyingFileSystem();
8
9 //creating command and associating with receiver
10 OpenFileCommand openFileCommand = new OpenFileCommand(fs);
11
12 //Creating invoker and associating with Command
13 FileInvoker file = new FileInvoker(openFileCommand);
14
15 //perform action on invoker object
16 file.execute();
17
18 WriteFileCommand writeFileCommand = new WriteFileCommand(fs);
19 file = new FileInvoker(writeFileCommand);
20 file.execute();
21
22 CloseFileCommand closeFileCommand = new CloseFileCommand(fs);
23 file = new FileInvoker(closeFileCommand);
24 file.execute();
25 }
26
27}
请注意,客户端负责创建适当类型的命令对象。例如,如果你想写一个文件,你不应该创建CloseFileCommand
对象。客户端程序还负责将接收器附加到命令,然后将命令附加到调用程序类。上述命令模式示例程序的输出是:
1Underlying OS is:Mac OS X
2Opening file in unix OS
3Writing file in unix OS
4Closing file in unix OS
命令模式类图
命令模式要点
- 命令是定义实现契约的命令设计模式的核心。
- 接收器实现与命令实现分开。
- 命令实现类选择要在Receiver对象上调用的方法,对于Receiver中的每个方法都将有一个命令实现。它充当接收者和动作方法之间的桥梁。
- Invoker类只是将客户端的请求转发给命令对象。
- 客户端负责实例化相应的命令和接收器实现,然后将它们关联在一起。
- 客户端还负责实例化Invoker对象,并将命令对象与其关联并执行action方法。
- 命令设计模式易于扩展,我们可以在接收器中添加新的操作方法,并在不更改客户端代码的情况下创建新的命令实现。
- Command设计模式的缺点是代码变得庞大而令人困惑,因为有大量的操作方法,而且有太多的关联。
命令设计模式JDK示例
Runnable interface(java.lang.Runnable)和Swing Action(javax.swing.Action)使用命令模式。