命令设计模式
命令模式是行为设计模式之一。命令设计模式用于在请求-响应模型中实现松耦合。
命令模式
在命令模式中,请求被发送到,invoker
调用者将其传递给封装的command
对象。命令对象将请求传递给适当的方法来Receiver
执行特定的操作。客户端程序创建接收器对象,然后将其附加到命令。然后它创建调用者对象并附加命令对象以执行操作。现在,当客户端程序执行操作时,它会根据命令和接收器对象进行处理。
命令设计模式示例
我们将研究一个可以实现命令模式的真实场景。假设我们想要提供一个文件系统实用程序,其中包含打开、写入和关闭文件的方法。此文件系统实用程序应支持多种操作系统,例如 Windows 和 Unix。要实现我们的文件系统实用程序,首先我们需要创建实际上将完成所有工作的接收器类。由于我们在 Java 中以接口的形式进行编码,因此我们可以拥有FileSystemReceiver
针对不同操作系统类型(例如 Windows、Unix、Solaris 等)的接口及其实现类。
命令模式接收器类
package com.journaldev.design.command;
public interface FileSystemReceiver {
void openFile();
void writeFile();
void closeFile();
}
FileSystemReceiver 接口定义了实现类的契约。为简单起见,我创建了两种接收器类,分别用于 Unix 和 Windows 系统。
package com.journaldev.design.command;
public class UnixFileSystemReceiver implements FileSystemReceiver {
@Override
public void openFile() {
System.out.println("Opening file in unix OS");
}
@Override
public void writeFile() {
System.out.println("Writing file in unix OS");
}
@Override
public void closeFile() {
System.out.println("Closing file in unix OS");
}
}
package com.journaldev.design.command;
public class WindowsFileSystemReceiver implements FileSystemReceiver {
@Override
public void openFile() {
System.out.println("Opening file in Windows OS");
}
@Override
public void writeFile() {
System.out.println("Writing file in Windows OS");
}
@Override
public void closeFile() {
System.out.println("Closing file in Windows OS");
}
}
您是否注意到了 Override 注释?如果您想知道为什么要使用它,请阅读Java 注释和覆盖注释的好处。现在我们的接收器类已经准备好了,我们可以开始实现我们的命令类。
命令模式接口和实现
我们可以使用接口或抽象类来创建基本命令,这是一个设计决定,取决于您的需求。我们使用接口,因为我们没有任何默认实现。
package com.journaldev.design.command;
public interface Command {
void execute();
}
现在我们需要为接收器执行的所有不同类型的操作创建实现。由于我们有三个操作,因此我们将创建三个命令实现。每个命令实现都会将请求转发给接收器的相应方法。
package com.journaldev.design.command;
public class OpenFileCommand implements Command {
private FileSystemReceiver fileSystem;
public OpenFileCommand(FileSystemReceiver fs){
this.fileSystem=fs;
}
@Override
public void execute() {
//open command is forwarding request to openFile method
this.fileSystem.openFile();
}
}
package com.journaldev.design.command;
public class CloseFileCommand implements Command {
private FileSystemReceiver fileSystem;
public CloseFileCommand(FileSystemReceiver fs){
this.fileSystem=fs;
}
@Override
public void execute() {
this.fileSystem.closeFile();
}
}
package com.journaldev.design.command;
public class WriteFileCommand implements Command {
private FileSystemReceiver fileSystem;
public WriteFileCommand(FileSystemReceiver fs){
this.fileSystem=fs;
}
@Override
public void execute() {
this.fileSystem.writeFile();
}
}
现在我们已经准备好接收器和命令实现,因此我们可以继续实现调用器类。
命令模式调用者类
Invoker 是一个简单的类,它封装了 Command 并将请求传递给命令对象来处理它。
package com.journaldev.design.command;
public class FileInvoker {
public Command command;
public FileInvoker(Command c){
this.command=c;
}
public void execute(){
this.command.execute();
}
}
我们的文件系统实用程序实现已准备就绪,我们可以开始编写一个简单的命令模式客户端程序。但在此之前,我将提供一种实用程序方法来创建适当的对象FileSystemReceiver
。由于我们可以使用System 类来获取操作系统信息,我们将使用它,否则我们可以使用Factory 模式根据输入返回适当的类型。
package com.journaldev.design.command;
public class FileSystemReceiverUtil {
public static FileSystemReceiver getUnderlyingFileSystem(){
String osName = System.getProperty("os.name");
System.out.println("Underlying OS is:"+osName);
if(osName.contains("Windows")){
return new WindowsFileSystemReceiver();
}else{
return new UnixFileSystemReceiver();
}
}
}
现在让我们创建使用文件系统实用程序的命令模式示例客户端程序。
package com.journaldev.design.command;
public class FileSystemClient {
public static void main(String[] args) {
//Creating the receiver object
FileSystemReceiver fs = FileSystemReceiverUtil.getUnderlyingFileSystem();
//creating command and associating with receiver
OpenFileCommand openFileCommand = new OpenFileCommand(fs);
//Creating invoker and associating with Command
FileInvoker file = new FileInvoker(openFileCommand);
//perform action on invoker object
file.execute();
WriteFileCommand writeFileCommand = new WriteFileCommand(fs);
file = new FileInvoker(writeFileCommand);
file.execute();
CloseFileCommand closeFileCommand = new CloseFileCommand(fs);
file = new FileInvoker(closeFileCommand);
file.execute();
}
}
请注意,客户端负责创建适当类型的命令对象。例如,如果您要写入文件,则不应创建CloseFileCommand
对象。客户端程序还负责将接收器附加到命令,然后将命令附加到调用者类。上述命令模式示例程序的输出为:
Underlying OS is:Mac OS X
Opening file in unix OS
Writing file in unix OS
Closing file in unix OS
命令模式类图
这是我们的文件系统实用程序实现的类图。
命令模式重点
- 命令是命令设计模式的核心,它定义了需要执行的契约。
- 接收器实现与命令实现是分开的。
- 命令实现类选择在接收方对象上调用的方法,接收方中的每个方法都会有一个命令实现。它充当接收方和操作方法之间的桥梁。
- Invoker 类只是将来自客户端的请求转发到命令对象。
- 客户端负责实例化适当的命令和接收器实现,然后将它们关联在一起。
- 客户端还负责实例化调用者对象并将命令对象与其关联并执行操作方法。
- 命令设计模式易于扩展,我们可以在接收器中添加新的操作方法并创建新的命令实现,而无需更改客户端代码。
- 命令设计模式的缺点是,由于操作方法数量众多且关联过多,代码变得庞大且混乱。
命令设计模式 JDK 示例
Runnable 接口(java.lang.Runnable)和 Swing Action(javax.swing.Action)使用命令模式。