命令模式
1.什么是命令模式
WIKI: 它把在稍后执行的一个动作或触发的一个事件所需要的所有信息封装到一个对象中。
2.实例
例如假如有一个万能遥控可以对任何东西发出任何命令
3.程序示例
public interface Command {
/**
* 执行命令
* @param target 执行命令的目标
*/
void doCommand(Target target);
void redoCommand();
void undoCommand();
}
/**
* 目标
*/
public interface Target {
/**
* 获取目标的名字
*/
String getTargetName();
}
/**
* 电视类
*/
public abstract class TvTarget implements Target{
/**
* 电视开关状态
*/
private boolean isTvOn;
private String tvName;
private int leastChannelNum = 0;
private int channelNum = 1;
public int getChannelNum() {
return channelNum;
}
@Override
public String getTargetName() {
return tvName;
}
public boolean isOn() {
return isTvOn;
}
protected void setTvOn(boolean tvOn) {
isTvOn = tvOn;
}
protected void setTvName(String tvName) {
this.tvName = tvName;
}
/**
* 切换频道
* 实际中不同品牌切换频道的逻辑并不相同
*/
public void changeChannel(int channelNum){
if(isOn()){
leastChannelNum = this.channelNum;
this.channelNum = channelNum;
System.out.println(String.format("已切换到%d频道~", channelNum));
}else {
System.out.println("请先开启电视机~");
}
}
public void reFreshChannel(){
System.out.println(String.format("刷新%d频道成功~", channelNum));
}
/**
* 返回上一个频道
*/
public void returnLeastChannel(){
if(isOn() && leastChannelNum != 0){
System.out.print("返回上一个频道:");
changeChannel(leastChannelNum);
}else {
System.out.println("请先开启电视机~");
}
}
}
public class AppleTv extends TvTarget{
public AppleTv(){
setTvName("苹果牌电视");
}
public void turnOn(){
setTvOn(true);
// ...
}
public void turnOff(){
setTvOn(false);
// ...
}
}
public class ChangeChannelCommand implements Command{
private int channelNum;
private TvTarget tvTarget;
public ChangeChannelCommand(int channelNum) {
this.channelNum = channelNum;
}
@Override
public void doCommand(Target target) {
this.tvTarget = (TvTarget) target;
tvTarget.changeChannel(channelNum);
}
@Override
public void redoCommand() {
tvTarget.reFreshChannel();
}
@Override
public void undoCommand() {
tvTarget.returnLeastChannel();
}
}
/**
* 万能遥控器
* 可以控制电视、洗衣机、冰箱、空调...
*/
public class AmazingRemoteControl {
// 待重新执行的命令
private Deque<Command> redoCommandList = new LinkedList<>();
// 待撤回的命令
private Deque<Command> undoCommandList = new LinkedList<>();
// 执行
public void executeCommand(Command command, Target target){
command.doCommand(target);
redoCommandList.add(command);
undoCommandList.add(command);
}
//撤回
public void undoCommand(){
if(!undoCommandList.isEmpty()){
undoCommandList.pollLast().undoCommand();
}
}
// 再次执行
public void redoCommand(){
if(!redoCommandList.isEmpty()){
redoCommandList.pollLast().redoCommand();
}
}
}
@Test
public void test(){
AmazingRemoteControl control = new AmazingRemoteControl();
Command command = new ChangeChannelCommand(10);
Command command2 = new ChangeChannelCommand(20);
Command command3 = new ChangeChannelCommand(30);
AppleTv tvTarget = new AppleTv();
// 关于电视的开关命令没写,可仿照ChangeChannelCommand写
tvTarget.turnOn();
control.executeCommand(command, tvTarget);
control.executeCommand(command2, tvTarget);
control.redoCommand();
control.undoCommand();
control.executeCommand(command3, tvTarget);
control.redoCommand();
control.undoCommand();
}
已切换到10频道~
已切换到20频道~
刷新20频道成功~
返回上一个频道:已切换到10频道~
已切换到30频道~
刷新30频道成功~
返回上一个频道:已切换到10频道~
4.总结
命令模式将命令和执行命令的实例解耦,使系统的扩展更加灵活,并借助列表实现了命令的再次执行和撤回。