命令设计模式

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

命令模式

在命令模式中,请求被发送给调用者,调用者将其传递给封装的命令对象。命令对象将请求传递给接收者的适当方法以执行特定的操作。客户程序创建接收者对象,然后将其附加到命令上。然后创建调用者对象并将命令对象附加以执行操作。现在,当客户程序执行操作时,它会根据命令和接收者对象进行处理。

命令设计模式实例

我们将看一个实际情境,可以在其中实施命令模式。假设我们想提供一个文件系统工具,用于打开、写入和关闭文件。这个文件系统工具应该支持多个操作系统,例如Windows和Unix。为了实现我们的文件系统工具,首先我们需要创建接收器类,实际执行所有工作。由于我们在Java中使用接口进行编码,我们可以有FileSystemReceiver接口及其在Windows、Unix、Solaris等不同操作系统版本上的实现类。

命令模式接收者类

package com.Olivia.design.command;

public interface FileSystemReceiver {

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

FileSystemReceiver接口定义了实现类的契约。为了简化起见,我创建了两种接收器类来与Unix和Windows系统配合使用。

package com.Olivia.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.Olivia.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注解和Override注解的好处。现在我们的接收器类已经准备好了,我们可以开始实现命令类了。

命令模式接口和实现方法

我们可以使用接口或抽象类来创建我们的基础命令,这是一个设计决策,取决于您的需求。我们选择使用接口,因为我们没有任何默认实现。

package com.Olivia.design.command;

public interface Command {

	void execute();
}

现在我们需要为接收器执行的所有不同类型的操作创建实现。由于我们有三个操作,我们将创建三个命令实现。每个命令实现将请求转发给接收器的相应方法。

package com.Olivia.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.Olivia.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.Olivia.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 是一个简单的类,它封装了命令并将请求传递给命令对象来处理。

package com.Olivia.design.command;

public class FileInvoker {

	public Command command;
	
	public FileInvoker(Command c){
		this.command=c;
	}
	
	public void execute(){
		this.command.execute();
	}
}

我们的文件系统实用程序实现已经准备就绪,我们可以开始编写一个简单的命令模式客户端程序。但在此之前,我将提供一个实用方法来创建适当的FileSystemReceiver对象。由于我们可以使用System类来获取操作系统信息,我们将使用它;否则,我们可以使用工厂模式根据输入返回适当的类型。

package com.Olivia.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.Olivia.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

命令模式类图

以下是我们文件系统工具实现的类图。

命令模式的重要要点

  • Command is the core of command design pattern that defines the contract for implementation.
  • Receiver implementation is separate from command implementation.
  • Command implementation classes chose the method to invoke on receiver object, for every method in receiver there will be a command implementation. It works as a bridge between receiver and action methods.
  • Invoker class just forward the request from client to the command object.
  • Client is responsible to instantiate appropriate command and receiver implementation and then associate them together.
  • Client is also responsible for instantiating invoker object and associating command object with it and execute the action method.
  • Command design pattern is easily extendible, we can add new action methods in receivers and create new Command implementations without changing the client code.
  • The drawback with Command design pattern is that the code gets huge and confusing with high number of action methods and because of so many associations.

命令设计模式JDK示例的释义如下:

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

发表回复 0

Your email address will not be published. Required fields are marked *


广告
将在 10 秒后关闭
bannerAds