命令模式:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。 类图: Receiver是具体的命令的接受者和执行者 Command 命令的接口 ConcreteCommand具体的命令,继承Command,实现接口方法,并含有一个Receiver来实现具体的命令; Invoker:要求该命令执行这个请求;调用者,将命令向后传递; 优点: 比较容易的设计一个命令队列 在需要的情况下,可以较容易地将命令记入日志; 允许接受请求的一方决定是否要否决请求。 可以容易的实现对请求的撤销和重做 加进新的具体的命令不影响其他类 使请求者与实现者解耦 代码: Command 接口:
public abstract class Command { protected Receiver receiver; public Command(Receiver receiver) { this.receiver = receiver; } public abstract void execute(); }ConcreteCommand类:
public class ConcreteCommand extends Command{ public ConcreteCommand(Receiver receiver) { super(receiver); } @Override public void execute() { receiver.action(); } }Receiver类:
public class Receiver { public void action() { System.out.println("执行请求"); } }Invoker类:
public class Invoker { private Command command; public void setCommand(Command command) { this.command = command; } public void executorComman() { command.execute(); } }Client类:
import org.junit.Test; public class Client { @Test public void commandTest() { Invoker invoker = new Invoker(); Receiver receiver = new Receiver(); Command command = new ConcreteCommand(receiver); invoker.setCommand(command); invoker.executorComman(); } }由上面代码可以看出Invoker 负责接受一个命令并将命令传递个真正的接收执行者Receiver来执行; 由于是命令模式,所以还可以将许多命令排队执行,将Invoker中的Command改为一个Command 的集合,如果命令还没有执行则可以撤销这个命令,当然也可以不满足条件拒绝执行这个命令,这些都可以在Invoker进行判断。 与策略模式比较: 策略模式关注的是算法替换的问题,一个新的算法投产,旧算法退休,或者提供多种算法由调用者自己选择使用,算法的自由更替是它实现的要点。换句话说,策略模式关注的是算法的完整性、封装性,只有具备了这两个条件才能保证其可以自由切换。 命令模式则关注的是解耦问题,如何让请求者和执行者解耦是它需要首先解决的,解耦的要求就是把请求的内容封装为一个一个的命令,由接收者执行。由于封装成了命令,就同时可以对命令进行多种处理,例如撤销、记录等。 在我们的例子中,策略模式中的抽象算法和具体算法与命令模式的接收者非常相似,但是它们的职责不同。策略模式中的具体算法是负责一个完整算法逻辑,它是不可再拆分的原子业务单元,一旦变更就是对算法整体的变更。 而命令模式则不同,它关注命令的实现,也就是功能的实现。例如我们在分支中也提到接收者的变更问题,它只影响到命令族的变更,对请求者没有任何影响,从这方面来说,接收者对命令负责,而与请求者无关。命令模式中的接收者只要符合六大设计原则,完全不用关心它是否完成了一个具体逻辑,它的影响范围也仅仅是抽象命令和具体命令,对它的修改不会扩散到模式外的模块。 当然,如果在命令模式中需要指定接收者,则需要考虑接收者的变化和封装,例如一个老顾客每次吃饭都点同一个厨师的饭菜,那就必须考虑接收者的抽象化问题。 策略模式适用于算法要求变换的场景,而命令模式适用于解耦两个有紧耦合关系的对象场合或者多命令多撤销的场景。
