命令模式
1. 介绍
命令模式(Command Pattern)
是一种行为型模式。将命令设计成对象,并为其指定命令的接收者和它要执行接收者的那个方法,当控制器接收到命令后,就执行命令。
简单理解:假如我们有一台电视机,它有切换到某个频道的功能,而现在又有三条命令:切换到cctv1、切换到cctv2、切换到cctv3,每条命令又绑定了电视机的切换到cctv1、cctv2、cctv3这些方法,当我们按下遥控器时,就执行命令,而每一条命令执行时就会调用电视机切换到某个频道的方法。
优点:
- 降低了耦合度。要想增加新的命令,只需要增加新的具体命令并为命令的执行者增加对应方法即可。
缺点:
- 可能会产生非常多具体的命令类。由于一个具体的命令都要为其设计一个类,如果具体的命令非常多,就会产生非常多的具体命令类。
2. 例子
有一个电视机类,这个类中有切换到cctv1、cctv2、cctv3这三个频道的方法,有一个Command抽象类,它是所有命令要继承的父类,它有类型为电视机的命令接收者,其中的execute()方法是抽象方法。现在有Cctv1Command具体命令类,实现了execute()方法,execute()方法会执行命令接收者(电视机对象)中切换到cctv1的这个方法。还有一个控制器类,接收一个命令就会执行这个命令中的execute()方法。
类图:
Command抽象类和它的几个子类:
它是所有的具体命令类的父类,其中的execute()方法为抽象方法。
package commandPattern;
/**
* 代表命令的抽象类
*
* @author jxd
* @since 2021-06-06
*/
public abstract class Command {
/**
* 命令的接收者是电视机
*/
protected Tv tv;
public Command(Tv tv) {
this.tv = tv;
}
/**
* 让具体的命令类来实现
*/
abstract void execute();
}
/**
* 切换到CCTV1的命令类,继承了Command抽象类
*
* @author jxd
* @since 2021-06-06
*/
class CommandCCTV1 extends Command {
public CommandCCTV1(Tv tv) {
super(tv);
}
@Override
void execute() {
tv.gotoCCTV1();
}
}
/**
* 切换到CCTV2的命令类,继承了Command抽象类
*
* @author jxd
* @since 2021-06-06
*/
class CommandCCTV2 extends Command {
public CommandCCTV2(Tv tv) {
super(tv);
}
@Override
void execute() {
tv.gotoCCTV2();
}
}
/**
* 切换到CCTV3的命令类,继承了Command抽象类
*
* @author jxd
* @since 2021-06-06
*/
class CommandCCTV3 extends Command {
public CommandCCTV3(Tv tv) {
super(tv);
}
@Override
void execute() {
tv.gotoCCTV3();
}
}
Tv类
代表的是电视机,是命令的接收者。
package commandPattern;
/**
* 电视机,也就是命令的接收者
* @author jxd
* @since 2021-06-06
*/
public class Tv {
public Tv() {
super();
}
public void gotoCCTV1() {
System.out.println("电视机已经切换到CCTV1");
}
public void gotoCCTV2() {
System.out.println("电视机已近切换到了CCTV2");
}
public void gotoCCTV3() {
System.out.println("电视机已近切换到了CCTV3");
}
}
TvController类:
代表的是电视机的遥控器,命令的调用者。
package commandPattern;
import java.util.Deque;
import java.util.LinkedList;
/**
* 遥控器类,也就是命令的调用者
*
* @author jxd
* @since 2021-06-06
*/
public class TvController {
/**
* 使用双端对列来保存历史执行命令
*/
private Deque<Command> history = new LinkedList<Command>();
/**
* 保存的历史命令条数
*/
private int historyNm;
public TvController(int savehistoryNumbers) {
setHistoryNm(savehistoryNumbers);
}
/**
* 换台方法
*
* @param command 要执行的换台命令
*/
public void ChangeChannel(Command command) {
command.execute();
if (history.size() == historyNm) {
history.removeFirst();
}
history.add(command);
}
/**
* 执行上一步命令
*/
public void back() {
Command temCommand = history.pollLast();
if (temCommand == null) {
System.out.println("历史记录为空!");
} else {
temCommand.execute();
}
}
public int getHistoryNm() {
return historyNm;
}
public void setHistoryNm(int historyNm) {
this.historyNm = historyNm;
}
}
测试方法:
package commandPattern;
import org.junit.Test;
public class TestJ {
/**
* 测试命令模式
*/
@Test
public void test1() {
//创建一台电视机
Tv myTv = new Tv();
//创建一个遥控器
TvController tvController = new TvController(2);
//遥控器接收一个换台的命令并执行
tvController.ChangeChannel(new CommandCCTV1(myTv));
//遥控器接收一个执行上一步命令
tvController.back();
tvController.back();
tvController.ChangeChannel(new CommandCCTV2(myTv));
tvController.ChangeChannel(new CommandCCTV3(myTv));
}
}
运行结果:
电视机已经切换到CCTV1
电视机已经切换到CCTV1
历史记录为空!
电视机已近切换到了CCTV2
电视机已近切换到了CCTV3
3. 总结
命令模式就是将命令作为对象,为命令指定执行者和要执行执行者中的那个方法,当控制器接收到命令后,就执行命令。