一、概述
命令模式(Command模式),它是将一个请求封装为一个对象,从而使得可以用不同的请求对客户进行参数化。这个定义不好理解,举个具体的例子,平时看电视的时候需要用到遥控器,当我们按下遥控器的时候其实就是在发命令,比如切换频道、调音量、开关机等等请求操作,那么我们就把这些请求操作封装成一个对象,客户端接收到哪个参数对象,就执行哪种操作,当然具体的操作还是在电视机中实现的。这样就使得命令请求发送者与操作实现者进行解耦,命令模式也是一种行为型模式。
命令模式是对命令的封装,每一个命令都是一个请求对象,它包含了4个关键的角色:
- 抽象命令角色:高度抽象命令,包含命令执行的抽象方法。
- 具体命令角色:一个具体的命令请求,实现了抽象命令角色接口,在具体的抽象方法中实现自己的请求逻辑。
- 命令接收者角色:接收者在接收到具体的命令后,执行相应的操作,这里接收者就是电视机。
- 命令请求者角色:负责调用命令对象执行请求,这里请求者就是遥控器。
接下来我们用代码来做说明,这样会更容易了解命令模式。
二、使用
首先我们创建抽象的命令角色,它是所有命令的高度抽象,并有一个发送命令请求的抽象方法。
/**
* 抽象命令角色
*/
public interface Command {
void excute();
}
然后是具体的命令角色,所有的具体命令都实现了抽象命令接口,并在抽象方法中实现了自己的逻辑。
/**
* 具体的命令角色——换台
*/
public class ChangeChannelCommand implements Command {
private static final String TAG = "XXX";
private TV tv;
public ChangeChannelCommand(TV tv){
this.tv = tv;
}
@Override
public void excute() {
Log.e(TAG, "这个台不好看,我要换台");
tv.changeChannel();
}
}
/**
* 具体的命令角色——减小音量
*/
public class DownVolumeCommand implements Command {
private static final String TAG = "XXX";
private TV tv;
public DownVolumeCommand(TV tv){
this.tv = tv;
}
@Override
public void excute() {
Log.e(TAG, "声音太大,我要减小音量");
tv.downVolume();
}
}
/**
* 具体的命令角色——加大音量
*/
public class UpVolumeCommand implements Command {
private static final String TAG = "XXX";
private TV tv;
public UpVolumeCommand(TV tv){
this.tv = tv;
}
@Override
public void excute() {
Log.e(TAG, "声音太小,我要加大音量");
tv.upVolume();
}
}
从上面具体的命令中可以看到,都持有了电视机(命令接收者角色)的引用,在执行命令的方法中调用了电视机的具体方法,因为所有的命令都是由命令接收者来最终完成了,所以来让命令接收者执行真正的操作。来看看电视机(命令接收者角色)具体代码。
/**
* 命令接收者角色——电视机
*/
public class TV {
private static final String TAG = "XXX";
public void downVolume() {
Log.e(TAG, "电视机——减小音量");
}
public void upVolume() {
Log.e(TAG, "电视机——加大音量");
}
public void changeChannel() {
Log.e(TAG, "电视机——换台");
}
}
最后是命令请求者角色,也就是遥控器,这里会发送相关的命令对象给电视机(命令接收者)。
/**
* 命令请求者角色——遥控器
*/
public class TVControl {
private Command command;
public TVControl(Command command){
this.command = command;
}
public void setCommand(Command command){
this.command = command;
}
//发送请求
public void doAction(){
command.excute();
}
}
我们来进行代码试。首先创建了电视机对象,再创建了具体的命令对象并将电视机对象传入,使得命令对象持有电视机对象的引用,最后是创建遥控器对象,并将命令对象传入,执行遥控器对象的doAction方法,发送命令,最后在电视机中执行操作。打印输出如下。
TV tv = new TV();
ChangeChannelCommand changeChannelCommand = new ChangeChannelCommand(tv);
DownVolumeCommand downVolumeCommand = new DownVolumeCommand(tv);
UpVolumeCommand upVolumeCommand = new UpVolumeCommand(tv);
TVControl control = new TVControl(changeChannelCommand);
control.doAction();
Log.e(TAG, "----------------------");
control.setCommand(downVolumeCommand);
control.doAction();
Log.e(TAG, "----------------------");
control.setCommand(upVolumeCommand);
control.doAction();
三、总结
命令模式使得命令的发送与接收解耦,这样使得代码容易维护和展;命令的添加很方便,并且可以方便的制定各种命令和利用现有命令组合出新的命令,如当需要创建比如开关机命令时,无需修改原逻辑代码,只需要创建一个新的命令对象;如果针对每一类具有共同接口的接收者制作一个调用者,可以控制命令的执行情况。
当然命令模式的缺点就是当命令较多时,也会同时增加类的数量,也就增加了系统的复杂性。
github地址:github.com/leewell5717…