Command pattern is to de-couple action invoker and action receiver, action invoker just simplely asks one command to execute and don't need to know who will be the action receiveror how to execute, this pattern can seperate developments apart and easy to maintain.
The key is between action invoker and receiver we package the command object, the command object will implement command interface. Each concrete command object will polymeric action receiver, normally it provides addCommand and undoCommand functions, so that we can execute a series of commands one by one, also can revert the commands in sequence, it's like we press CTRL+Z to undo the operations in word or excel.
Pattern has several roles, invoker, concrete command, receiver. Below is one real example, we can see invoker has no relationship with action receiver but only talks to the command object,
We have a storage company, currently main products are rice and cement, if rice truck comes, we need to load rice; if cement truck comes, we load cement,
So we have abstact concept, ICommand,
public interface ICommand {
void execute();
void undo();
}
And concreate command will be RiceCommand and CementComand, it will polymeric the action receiver, RiceWorker and CementWorker
public class RiceCommand implements ICommand {
private RiceWorker riceWorker;
public RiceCommand(RiceWorker riceWorker) {
this.riceWorker = riceWorker;
}
@Override
public void execute() {
riceWorker.load();
}
@Override
public void undo() {
riceWorker.unload();
}
}
public class CementCommand implements ICommand {
private CementWorker cementWorker;
public CementCommand(CementWorker cementWorker) {
this.cementWorker = cementWorker;
}
@Override
public void execute() {
cementWorker.load();
}
@Override
public void undo() {
cementWorker.unload();
}
}
When trucks come, our company manager will call necessary commands, but if anything is wrong, we also can roll back all commands.
public class Invoker {
private List<ICommand> commandList;
private List<ICommand> undoCommandList;
public Invoker() {
commandList = new ArrayList<>();
undoCommandList = new ArrayList<>();
}
public List<ICommand> addCommand(ICommand command) {
this.commandList.add(command);
return commandList;
}
public List<ICommand> addUndoCommand(ICommand command) {
this.undoCommandList.add(command);
return undoCommandList;
}
public void run() {
this.commandList.forEach(command -> command.execute());
}
public void undo(){
this.undoCommandList.forEach(command -> command.undo());
}
}