命令模式将请求发送者与请求接收者解耦,在发送者与接收者之间引入命令对象,将发送者的请求封装在命令对象中,请求发送者经过命令对象来间接引用接收者,使得系统具备更好的灵活性,用户能够根据须要为请求发送者增长新的命令对象而无须修改原有系统html
举个现实生活中的例子,开关是请求的发送者,电灯是请求的接收者,它们之间不存在直接的耦合关系,而是经过电线链接到一块儿,开关不须要知道如何将开灯或关灯请求传输给电灯,而是经过电线来完成这项功能。java
此时能够理解为电线充当封装请求的命令对象,开关若是开则电线通电,并调用电灯的开灯方法,反之则关灯。不一样电线能够链接不一样的请求接收者,所以只需更换一根电线,相同的开关便可操做不一样的电器设备。编程
在软件设计中,咱们也像上述例子同样,常常须要向某些对象发送请求,可是不知道请求接收者是谁,也不知道被请求的操做是哪一个,咱们只需指定具体的请求接收者便可,此时,可使用命令模式使请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用更加啊灵活。设计模式
请一个请求封装为一个对象,从而使咱们可用不一样请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操做。命令模式是一种对象行为型模式,其别名为动做(Action)模式或事务(Transaction)模式ide
Command(抽象命令类)学习
通常是接口,其中声明了用于执行请求的 execute() 等方法,经过这些方法调用请求接收者的相关操做测试
ConcreteCommand(具体命令类)this
是抽象命令类的子类,实如今抽象命令类中声明的方法。它对应具体接收者对象,绑定接收者对象的动做。在实现 execute() 方法时将调用接收者对象的相关操做(Action)设计
Invoker(调用者)3d
即请求的发送者,又称请求者,经过命令对象来执行请求。一个调用者并不须要再设计时肯定其接收者,所以它与抽象命令类之间只存在关联关系。程序运行时调用具体命令对象的 execute() 方法,间接调用接收者的相关操做
Receiver(接收者)
执行者执行与请求相关的操做,它具体实现对请求的业务处理
Client(客户类)
客户类中需建立调用者对象和具体命令对象,再建立具体命令对象时指定其对应接收者,发送者和接收者之间无直接关系,透过具体命令对象实现间接调用
命令模式的本质其实就是将命令(Command)、发出命令的责任(Invoker)和执行命令的责任(Recevier)分隔开。请求的一方发出请求,要求执行一个操做,接收的一方收到请求,并执行操做,请求的一方没必要知道接收请求一方的任何细节。
命令模式的关键在于引入抽象命令接口,调用者针(Invoker)对抽象命令接口编程,只有实现具体命令类才能与对应接收者相关联。每一个具体命令类把接收者(Recevier)做为一个实例变量存储,从而指定接收者,并调用对应的请求处理方法
能够经过顺序图来进一步理解命令模式中对象之间的相互关系。
电视机是请求接收者,遥控器是请求发送者,遥控器上有一些不一样按钮,对应电视机的不一样操做,分别是:打开电视机、关闭电视机和切换频道。
接收者类 Television(电视机类)
public class Televison { public void open() { System.out.println("打开电视机"); } public void close() { System.out.println("关闭电视机"); } public void changeChannel() { System.out.println("切换电视频道"); } }
抽象命令类 AbstractCommand(命令类)
public interface AbstractCommand { public void execute(); }
具体命令类 TVOpenCommand(电视机打开命令类)
public class TVOpenCommand implements AbstractCommand { private Televison tv; public TVOpenCommand() { tv = new Televison(); } @Override public void execute() { tv.open(); } }
具体命令类 TVCloseCommand(电视机关闭命令类)
public class TVCloseCommand implements AbstractCommand { private Televison tv; public TVCloseCommand() { tv = new Televison(); } @Override public void execute() { tv.close(); } }
具体命令类 TVChangeCommand(电视机频道切换命令类)
public class TVChangeCommand implements AbstractCommand { private Televison tv; public TVChangeCommand() { tv = new Televison(); } @Override public void execute() { tv.changeChannel(); } }
调用者类 Controller(遥控器类)
public class Controller { private AbstractCommand openCommand, closeCommand, changeCommand; public Controller(AbstractCommand openCommand, AbstractCommand closeCommand, AbstractCommand changeCommand) { this.openCommand = openCommand; this.closeCommand = closeCommand; this.changeCommand = changeCommand; } public void open() { openCommand.execute(); } public void change() { changeCommand.execute(); } public void close() { closeCommand.execute(); } }
客户端测试类 Client
public class Client { public static void main(String[] args) { AbstractCommand openCommand, closeCommand, changeCommand; openCommand = new TVOpenCommand(); closeCommand = new TVCloseCommand(); changeCommand = new TVChangeCommand(); Controller controller = new Controller(openCommand, closeCommand, changeCommand); controller.open(); controller.change(); controller.close(); } }
运行结果
命令模式优势:
命令模式缺点:
咱们能够经过对命令类进行修改使得系统支持撤销操做和恢复操做,,抽象命令类(AbstractCommand)声明一个 undo() 方法
public interface AbstractCommand { public void undo(); public void execute(); }
具体命令类(ConcreteCommand)实如今抽象命令类(AbstractCommand)中声明的 execute() 和 undo() 方法
public class ConcreteCommand implements AbstractCommand { private Receiver receiver; public ConcreteCommand() { receiver = new Receiver(); } @Override public void execute() { receiver.method; } @Override public void undo() { // 撤销 execute() 操做 } }
调用者(Invoker)照常引用一个抽象命令 AbstractCommand 类型的对象 command,经过该 command 对象间接调用接收者 Receiver 类的业务方法
public class Invoker { private AbstractCommand command; public Invoker(AbstractCommand command) { this.openCommand = openCommand; } public void method() { command.execute(); } public void undo() { // 撤销操做 } }
上述实例只能实现一步撤销操做,由于没有保存命令对象的历史状态,能够经过引入一个命令集合或其余方式来存储中间状态,从而实现屡次撤销操做
宏命令又称组合命令,它是命令模式和组合模式联用的产物。宏命令也是一个具体命令,不过它包含了对其余命令对象的引用,在调用宏命令的 execute() 方法,将递归调用它所包含的每一个成员命令的 execute() 方法。一个宏命令的成员对象能够是简单命令,也能够继续是宏命令。