Command design pattern is used to implement loose coupling in a request-response model.
命令设计模式用于 在请求-响应模型中实现松耦合。
In command pattern, the request is send to the invoker and invoker pass it to the encapsulated command object.
Command object passes the request to the appropriate method of Receiver to perform the specific action.
在命令模式中,请求发送给invoker ,invoker 将其传递给封装的 command object。
command object 将请求传递给 Receiver 的适当方法,以执行特定的操作。
The client program create the receiver object and then attach it to the Command. Then it creates the invoker object and attach the command object to perform an action.
Now when client program executes the action, it’s processed based on the command and receiver object.
客户端程序创建 receiver object ,然后将其附加到Command。然后它创建 invoker object 并附加 command object 以执行操作。
现在,当客户端程序执行操作时,它将基于 command object 和 receiver object 进行处理。
Command Pattern Receiver Classes
public interface A1_FileSystemReceiver {
void openFile();
void writeFile();
void closeFile();
}
ublic class A2_UnixFileSystemReceiver implements A1_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");
}
}
public class A3_WindowsFileSystemReceiver implements A1_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");
}
}
Command Pattern Interface and Implementations
We can use interface or abstract class to create our base Command, it’s a design decision and depends on your requirement.
We are going with interface because we don’t have any default implementations.
base Command 可以用接口和抽象方法,如果没有common 或者 default implementations就用接口就可以了
public interface A4_Command {
void execute();
}
public class A5_OpenFileCommand implements A4_Command {
private A1_FileSystemReceiver fileSystem;
public A5_OpenFileCommand(A1_FileSystemReceiver fs){
this.fileSystem=fs;
}
@Override
public void execute() {
this.fileSystem.openFile();
}
}
public class A6_WriteFileCommand implements A4_Command {
private A1_FileSystemReceiver fileSystem;
public A6_WriteFileCommand(A1_FileSystemReceiver fs){
this.fileSystem=fs;
}
@Override
public void execute() {
this.fileSystem.writeFile();
}
}
public class A7_CloseFileCommand implements A4_Command {
private A1_FileSystemReceiver fileSystem;
public A7_CloseFileCommand(A1_FileSystemReceiver fs){
this.fileSystem=fs;
}
@Override
public void execute() {
this.fileSystem.closeFile();
}
}
Now we have receiver and command implementations ready, so we can move to implement the invoker class.
现在我们已经准备好了receiver implementations 和command implementations,因此我们可以开始实现invoker implementations
Command Pattern Invoker Class
Invoker是一个简单的类,封装Command并将请求传递给Command对象以处理它。
public class A8_FileInvoker {
public A4_Command command;
public A8_FileInvoker(A4_Command c){
this.command=c;
}
public void execute(){
this.command.execute();
}
}
provide a utility method to create the appropriate FileSystemReceiver object.
Since we can use System class to get the operating system information, we will use this or else we can use Factory pattern to return appropriate type based on the input.
public static A1_FileSystemReceiver getUnderlyingFileSystem(){
String osName = System.getProperty("os.name");
System.out.println("Underlying OS is:"+osName);
if(osName.contains("Windows")){
return new A3_WindowsFileSystemReceiver();
}else{
return new A2_UnixFileSystemReceiver();
}
}
Let’s move now to create our command pattern example client program that will consume our file system utility.
public static void main(String[] args) {
//Creating the receiver object
A1_FileSystemReceiver fileSystem = A9_FileSystemReceiverUtil.getUnderlyingFileSystem();
//creating command and associating with receiver
A5_OpenFileCommand openFileCommand = new A5_OpenFileCommand(fileSystem);
//Creating invoker and associating with Command
A8_FileInvoker fileInvoker = new A8_FileInvoker(openFileCommand);
//perform action on invoker object
fileInvoker.execute();
A6_WriteFileCommand writeFileCommand = new A6_WriteFileCommand(fileSystem);
fileInvoker = new A8_FileInvoker(writeFileCommand);
fileInvoker.execute();
A7_CloseFileCommand closeFileCommand = new A7_CloseFileCommand(fileSystem);
fileInvoker = new A8_FileInvoker(closeFileCommand);
fileInvoker.execute();
}
结果
Underlying OS is:Windows 7
Opening file in Windows OS
Writing file in Windows OS
Closing file in Windows OS
Important Points
Receiver implementation is separate from command implementation.
接收方实现与命令实现是分开的。
Command is the core of command design pattern that defines the contract for 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.
命令实现类选择接收器对象上的方法,对于 receiver object中的每个方法都有一个命令实现。
它是receiver 和 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.
Command设计模式的缺点是代码会变得非常庞大,并且会因为大量的操作方法和太多的关联而产生混淆。