命令模式 详解
定义
旨在将方法调用、请求或操作封装到单一对象中,从而根据我们不同的请求对客户进行参数化和传递可供执行的方法调用。此外,这种模式将调用操作的对象与知道如何实现该操作的对象解耦,并在交换出具体类(对象)方面提供更大的整体灵活性;
它为我们提供了一种分离职责的手段,这些职责包括从执行命令的任意地方发布命令以及将该职责转而委托给不同对象;
行为型模式
角色
- 命令角色(Command):是一个抽象类,类中对需要执行的命令进行声明,一般来说是对外公布一个excute用来实行命令;
- 具体命令角色(ConcreteCommand):实现类,对抽象类中声明的方法进行实现;
- 调用者(Invoker): 调用者,负责调用命令;
- 接受者(Recevie): 接受者,负责接收命令并且执行命令;
- 客户端(Client): 最终的客户端调用类;
从网上找到的例图
适用场景
- 使用命令模式作为“CallBack”在面向对象系统中的替代。“CallBack”讲的便是先将一个函数登记上,然后在以后调用此函数;
- 需要在不同的时间指定请求、将请求排队。一个命令对象和原先的请求发出者可以有不同的生命期。换言之,原先的请求发出者可能已经不在了,而命令本身仍然是活动的。这时命令的接收者可以是在本地,也可以是在网络的另外一个地址。命令对象可以在串形化之后传送到另外一台机器上;
- 系统需要支持命令的撤销操作,命令对象可以把状态存储起来,等到客户端需要撤销命令所产生的效果时,可以调用撤销方法,把命令所产生的效果撤销掉;还有恢复操作,以供客户端在需要的时候,再重新实施命令效果;
- 系统需要将一组操作组合在一起,即支持宏命令;
- 如果一个系统要将系统中所有的数据更新到日志里,以便在系统崩溃时,可以根据日志里读回所有的数据更新命令,重新调用Execute方法一条一条执行这些命令,从而恢复系统在崩溃前所做的数据更新;
例子
比如操控电视,这就是个典型的命令模式;电视作为接受者,被遥控器这个调用者操控,遥控器又有多个命令,它们有统一的接口;都会被遥控器调用;
实现代码
/**
* Created by George on 16/7/2.
*/
//命令接口
var Command = function () {
this.execute = function () {
};
};
//命令接收者Receiver
var TV = function () {
this.curChannel = 0;
this.turnOn = function () {
console.log("the tv is on");
};
this.turnOff = function () {
console.log("the tv is off");
};
this.changeChannel = function (channel) {
this.curChannel = channel;
console.log("now the tv is " + this.curChannel);
};
};
//开机命令
var CommandOn = function (tv) {
Command.apply(this);
this.tv = tv;
this.execute = function () {
this.tv.turnOn();
};
};
//关机命令
var CommandOff = function (tv) {
Command.apply(this);
this.tv = tv;
this.execute = function () {
this.tv.turnOff();
};
};
//切换频道命令
var CommandChange = function (tv, channel) {
Command.apply(this);
this.tv = tv;
this.channel = channel;
this.execute = function () {
this.tv.changeChannel(this.channel);
};
};
//遥控器作为Invoker
var Control = function (onCommand, offCommand, changeCommand) {
this.onCommand = onCommand;
this.offCommand = offCommand;
this.changeCommand = changeCommand;
this.turnOn = function () {
this.onCommand.execute();
};
this.turnOff = function () {
this.offCommand.execute();
};
this.changeChannel = function () {
this.changeCommand.execute();
};
};
//电视
var tv = new TV();
//开电视命令
var commandOn = new CommandOn(tv);
//关电视命令
var commandOff = new CommandOff(tv);
//切换命令
var commandChange = new CommandChange(tv, 2);
//遥控器
var control = new Control(commandOn, commandOff, commandChange);
control.turnOn();
control.turnOff();
control.changeChannel();
- 命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分隔开;
- 每一个命令都是一个操作:请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作;
- 命令模式允许请求的一方和接收的一方独立分开,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是如何被接收,以及操作是否被执行,何时被执行以及执行内容;
- 命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递;
- 命令模式的关键在于引入了抽象命令接口,而且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能接收者相关联;
优缺点
- 将调用操作的对象和知道如何实现该操作的对象解耦;
- Command是头等对象,可以像其它对象一样被操作和扩展;
- 可将多个命令装配成一个符合命令;
- 调用同一方法实现不同的功能;
注意的是
- 如果存在过多的具体命令,这将会影响命令模式的使用;
![](https://i.loli.net/2018/11/17/5beff4d639cbb.jpg)
关注公众号:数据结构与算法那些事儿,每天一篇数据结构与算法