指令设计模式

时间:2020-02-23 14:41:16  来源:igfitidea点击:

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

命令模式

在命令模式中,请求被发送到"调用者",调用者将其传递给封装的"命令"对象。

命令对象将请求传递给" Receiver"的适当方法以执行特定操作。

客户端程序创建接收器对象,然后将其附加到命令。
然后,它创建调用者对象并附加命令对象以执行操作。

现在,当客户端程序执行操作时,将根据命令和接收器对象对其进行处理。

命令设计模式示例

我们将看一个现实生活中可以实现Command模式的场景。
假设我们要为文件系统实用程序提供打开,写入和关闭文件的方法。
此文件系统实用程序应支持多种操作系统,例如Windows和Unix。

要实现我们的文件系统实用程序,首先,我们需要创建实际将完成所有工作的接收器类。

由于我们使用Java中的接口进行编码,因此我们可以拥有" FileSystemReceiver"接口,以及针对不同操作系统(例如Windows,Unix,Solaris等)的实现类。

命令模式接收器类

package com.theitroad.design.command;

public interface FileSystemReceiver {

	void openFile();
	void writeFile();
	void closeFile();
}

FileSystemReceiver接口定义实现类的协定。
为简单起见,我创建了两种类型的接收器类以与Unix和Windows系统一起使用。

package com.theitroad.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.theitroad.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注释并覆盖注释的好处。

现在我们的接收器类已经准备好了,我们可以开始实现Command类了。

命令模式接口和实现

我们可以使用接口或者抽象类来创建基本Command,这是设计决定,取决于您的要求。

我们将使用界面,因为我们没有任何默认实现。

package com.theitroad.design.command;

public interface Command {

	void execute();
}

现在,我们需要为接收器执行的所有不同类型的操作创建实现。
由于我们有三个动作,因此我们将创建三个Command实现。
每个Command实现都会将请求转发到适当的接收方方法。

package com.theitroad.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.theitroad.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.theitroad.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并将请求传递给Command对象以对其进行处理。

package com.theitroad.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.theitroad.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.theitroad.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类仅将来自客户端的请求转发到命令对象。

  • 客户负责实例化适当的命令和接收器实现,然后将它们关联在一起。

  • 客户端还负责实例化调用者对象并将命令对象与其关联,并执行action方法。

  • 命令设计模式易于扩展,我们可以在接收器中添加新的操作方法并创建新的Command实现,而无需更改客户端代码。

  • Command设计模式的缺点是,由于大量的关联,代码变得庞大且与大量的操作方法混淆。

命令设计模式JDK示例

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