命令设计模式

指挥模式是行为设计模式的一种。命令设计模式用于在请求-响应模型中实现松耦合

命令模式

命令设计模式,命令pattern在命令模式中,请求被发送到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 annotationsOverride 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

命令模式类图

以下是我们的文件系统实用程序实现的类图。命令设计模式,Java中的命令模式,命令模式类图,命令Pattern

命令模式要点

  • 命令是定义实现契约的命令设计模式的核心。
  • 接收器实现与命令实现分开。
  • 命令实现类选择要在Receiver对象上调用的方法,对于Receiver中的每个方法都将有一个命令实现。它充当接收者和动作方法之间的桥梁。
  • Invoker类只是将客户端的请求转发给命令对象。
  • 客户端负责实例化相应的命令和接收器实现,然后将它们关联在一起。
  • 客户端还负责实例化Invoker对象,并将命令对象与其关联并执行action方法。
  • 命令设计模式易于扩展,我们可以在接收器中添加新的操作方法,并在不更改客户端代码的情况下创建新的命令实现。
  • Command设计模式的缺点是代码变得庞大而令人困惑,因为有大量的操作方法,而且有太多的关联。

命令设计模式JDK示例

Runnable interface(java.lang.Runnable)和Swing Action(javax.swing.Action)使用命令模式。

Published At
Categories with 技术
comments powered by Disqus