命令模式定义
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
作用
命令模式主要应用于将行为调用者与实现者解耦。讲发出请求和执行对象分开来。
例如:比如我们以前惯用的写代码的方式是LogicProcess logic = new LogicProcess(); 然后紧接着调用实现方法logic.process(),这种写法其实非常普遍,但这种写法把行为调用者和行为实现者耦合在了一起,一般情况下并没有什么问题的,但当调用逻辑比较复杂或则调用行为有多种实现时就非常不利于程序的扩展。
UML图:
命令模式的参与角色:
(1)抽象命令角色(Command):抽象命令,包含命令执行的抽象方法
(2)命令接收者(Receiver):命令接收者角色,它包含所有命令的具体行为实现方法。
(3)具体命令角色(ConcreteCommand):它包含一个命令接收者对象,并调用接收者的对象相应实现方法。
(4)命令调用者角色(Invoker):提供给客户端调用,接收客户端所传递的具体命令对象。
Java代码实现:
抽象命令角色:Command.java
/**
* 抽象命令接口
*/
public interface Command {
void execute();
}
命令接收者角色:Document.java
/** * 命令接收者 Receiver */ public class Document { public static StringBuffer sbr = new StringBuffer(); public static int count = 0; public void undo(){ System.out.println("调用撤销实现方法,字符串递减"); sbr.deleteCharAt(sbr.length()-1); count --; System.out.println("当前文本为:" + sbr.toString()); } public void redo(){ System.out.println("调用恢复实现方法,字符串递加"); this.sbr.append(count); count ++; System.out.println("当前文本为:" + sbr.toString()); } public void add(){ System.out.println("调用执行实现方法,字符串递加"); this.sbr.append(count); count ++; System.out.println("当前文本为:" + sbr.toString()); } }具体命令角色:AddCommand.java
/**
* 执行命令实现类
*/
public class AddCommand implements Command {
public Document doucment;
public AddCommand(Document document){
this.doucment = document;
}
@Override
public void execute() {
this.doucment.add();
}
}
具体命令角色:UndoCommand.java
/** * 撤销命令实现类 */ public class UndoCommand implements Command { public Document doucment; public UndoCommand(Document document){ this.doucment = document; } @Override public void execute() { this.doucment.undo(); } }
具体命令角色:RedoCommand.java
/**
* 恢复命令实现类
*/
public class RedoCommand implements Command {
public Document doucment;
public RedoCommand(Document document){
this.doucment = document;
}
@Override
public void execute() {
this.doucment.redo();
}
}
调用者角色:Invoker.java
public class Invoker { public Command command; public void setCommand(Command cmd){ this.command = cmd; } public void execute(){ this.command.execute(); } }最后可以写一个测试来就知道使用命令模式的好处了
public class TestMain { public static void main(String args[]){ Document doc = new Document(); //文档实体对象 AddCommand addCmd = new AddCommand(doc); //具体命令实体对象 UndoCommand undoCmd = new UndoCommand(doc); //具体命令实体对象 RedoCommand redoCmd = new RedoCommand(doc); //具体命令实体对象 Invoker invoker = new Invoker(); //调用者对象 invoker.setCommand(addCmd); invoker.execute(); invoker.setCommand(addCmd); invoker.execute(); invoker.setCommand(undoCmd); invoker.execute(); invoker.setCommand(redoCmd); invoker.execute(); } }
总结
- 命令模式将发出请求的对象和执行请求的对象解耦
- 在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接受者和一个或一组动作。
- 调用者通过命令对象的 execute() 发出请求,这会使得接受者的动作被调用。
- 命令模式可为多种行为提供统一的调用入口,便于程序对行为的管理和控制。
- 命令模式将行为的具体实现封装起来,客户端无需关心行为的具体实现。
- 命令可以支持撤销,做法是实现一个 undo()方法来回到 execute()被执行前的状态。