命令模式(Command Pattern)
命令模式(Command Pattern)
命令模式是一种行为型设计模式,它将请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化。命令模式允许你将请求的发送者和接收者解耦,支持请求的排队、记录日志以及撤销操作。
模式结构
- 命令接口(Command)
定义执行操作的接口,通常包含一个execute()
方法。 - 具体命令类(Concrete Command)
实现命令接口,封装具体的操作。它通常持有一个接收者对象,并将请求转发给接收者。 - 接收者(Receiver)
负责执行具体的操作。命令对象会将请求转发给接收者。 - 调用者(Invoker)
持有命令对象,并调用命令对象的execute()
方法来执行请求。 - 客户端(Client)
创建命令对象并设置其接收者,然后将命令对象传递给调用者。
代码示例
1. 命令接口(Command)
// 命令接口:定义执行操作的接口
interface Command {
void execute();
}
2. 具体命令类(Concrete Command)
// 具体命令类:打开文件命令
class OpenFileCommand implements Command {
private final FileSystemReceiver receiver;
public OpenFileCommand(FileSystemReceiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.openFile();
}
}
// 具体命令类:写入文件命令
class WriteFileCommand implements Command {
private final FileSystemReceiver receiver;
public WriteFileCommand(FileSystemReceiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.writeFile();
}
}
// 具体命令类:关闭文件命令
class CloseFileCommand implements Command {
private final FileSystemReceiver receiver;
public CloseFileCommand(FileSystemReceiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.closeFile();
}
}
3. 接收者(Receiver)
// 接收者接口:定义执行操作的方法
interface FileSystemReceiver {
void openFile();
void writeFile();
void closeFile();
}
// 具体接收者:Unix 文件系统接收者
class UnixFileSystemReceiver implements FileSystemReceiver {
@Override
public void openFile() {
System.out.println("在 Unix 系统中打开文件 ...");
}
@Override
public void writeFile() {
System.out.println("在 Unix 系统中写入文件 ...");
}
@Override
public void closeFile() {
System.out.println("在 Unix 系统中关闭文件 ...");
}
}
// 具体接收者:Windows 文件系统接收者
class WindowsFileSystemReceiver implements FileSystemReceiver {
@Override
public void openFile() {
System.out.println("在 Windows 系统中打开文件 ...");
}
@Override
public void writeFile() {
System.out.println("在 Windows 系统中写入文件 ...");
}
@Override
public void closeFile() {
System.out.println("在 Windows 系统中关闭文件 ...");
}
}
4. 调用者(Invoker)
// 调用者:持有命令对象并调用其 execute() 方法
class FileInvoker {
private final Command command;
public FileInvoker(Command command) {
this.command = command;
}
public void execute() {
command.execute();
}
}
5.代码示例
public class CommandPattern {
public static void main(String[] args) {
// 根据操作系统选择接收者
String osName = System.getProperty("os.name");
System.out.println("当前操作系统: " + osName);
FileSystemReceiver receiver;
if (osName.contains("Windows")) {
receiver = new WindowsFileSystemReceiver();
} else {
receiver = new UnixFileSystemReceiver();
}
// 创建命令对象
Command open = new OpenFileCommand(receiver);
Command write = new WriteFileCommand(receiver);
Command close = new CloseFileCommand(receiver);
// 创建调用者并执行命令
FileInvoker invoker = new FileInvoker(open);
invoker.execute();
invoker = new FileInvoker(write);
invoker.execute();
invoker = new FileInvoker(close);
invoker.execute();
}
}
输出结构
当前操作系统: Windows
在 Windows 系统中打开文件 ...
在 Windows 系统中写入文件 ...
在 Windows 系统中关闭文件 ...
应用场景
- 参数化对象
当需要通过操作来参数化对象时,可以使用命令模式。命令模式将特定的方法调用转化为独立对象,使得请求的发送者和接收者解耦。 - 请求排队或记录日志
当需要将操作放入队列中、记录操作日志或远程执行操作时,可以使用命令模式。命令对象可以被序列化并保存,方便后续恢复或传输。 - 撤销操作
当需要实现操作的撤销功能时,可以使用命令模式。命令模式可以通过保存操作的历史记录来实现撤销功能。
在Java中的应用
-
java.lang.Runnable
Java 中的
Runnable
接口就是一个典型的命令模式应用。Runnable
接口定义了一个run()
方法,具体的任务可以通过实现Runnable
接口来封装。
优缺点
优点
- 解耦请求的发送者和接收者
命令模式将请求的发送者和接收者解耦,使得请求的发送者不需要知道具体的接收者。 - 支持撤销和恢复操作
命令模式可以通过保存操作的历史记录来实现撤销和恢复功能。 - 支持请求的排队和日志记录
命令模式可以将请求封装为对象,方便请求的排队和日志记录。
缺点
- 增加代码复杂性
命令模式引入了额外的类和接口,增加了代码的复杂性。 - 可能产生大量具体命令类
如果系统中需要处理大量的命令,可能会导致具体命令类的数量过多。
总结
命令模式通过将请求封装为对象,使得请求的发送者和接收者解耦。它适用于需要通过操作来参数化对象、支持请求的排队和日志记录、以及实现撤销操作的场景。尽管它可能会增加代码的复杂性,但其优点在于提高了代码的灵活性和可扩展性。在Java中,命令模式广泛应用于任务调度和事件处理等场景。