命令模式
行为型模式
命令模式(Command Pattern)是一种数据驱动的设计模式,请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
介绍
意图: 将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
主要解决: 在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
何时使用: 在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
如何解决: 通过调用者调用接受者执行命令,顺序:调用者→接受者→命令。
关键代码: 定义三个角色:1、received 真正的命令执行对象 2、Command 3、invoker 使用命令对象的入口
具体实现
我们买了一套智能家电,有照明灯,风扇,冰箱,电视等等,我们只要在手机上安装app就可以控制这些家电,但我们不想针对每一种家电都安装一个app来分别控制,我们希望一个app就可以控制全部的家电。
在该案例中我们采用遥控器形式来展现命令模式。
第一步:创建命令接口
public interface Command {
//执行命令
void execute();
//撤销命令
void undo();
}
第二步:创建电灯和电视机命令执行对象
public class LightReceiver {
public void on(){
System.out.println("电灯打开了...");
}
public void off(){
System.out.println("电灯关闭了...");
}
}
public class TVReceiver {
public void on() {
System.out.println("电视机打开了...");
}
public void off() {
System.out.println("电视机关闭了...");
}
}
第三步:创建电灯和电视机操作实现类
public class LightOnCommand implements Command {
//聚合LightReceiver
private LightReceiver lightReceiver;
public LightOnCommand(LightReceiver lightReceiver) {
this.lightReceiver = lightReceiver;
}
@Override
public void execute() {
System.out.println("调用接受者的方法...");
lightReceiver.on();
}
@Override
public void undo() {
System.out.println("调用接受者的方法...");
lightReceiver.off();
}
}
public class LightOffCommand implements Command {
//聚合LightReceiver
private LightReceiver lightReceiver;
public LightOffCommand(LightReceiver lightReceiver) {
this.lightReceiver = lightReceiver;
}
@Override
public void execute() {
System.out.println("调用接受者的方法...");
lightReceiver.off();
}
@Override
public void undo() {
System.out.println("调用接受者的方法...");
lightReceiver.on();
}
}
public class TVOffCommand implements Command {
//聚合TVReceiver
private TVReceiver tvReceiver;
public TVOffCommand(TVReceiver tvReceiver) {
this.tvReceiver = tvReceiver;
}
@Override
public void execute() {
System.out.println("调用接受者的方法...");
tvReceiver.off();
}
@Override
public void undo() {
System.out.println("调用接受者的方法...");
tvReceiver.on();
}
}
public class TVOnCommand implements Command {
//聚合TV
private TVReceiver tvReceiver;
public TVOnCommand(TVReceiver tvReceiver) {
this.tvReceiver = tvReceiver;
}
@Override
public void execute() {
System.out.println("调用接受者的方法...");
tvReceiver.on();
}
@Override
public void undo() {
System.out.println("调用接受者的方法...");
tvReceiver.off();
}
}
/**
* 没有任何命令,即空执行:用于初始化每个按钮,当调用空命令时,对象什么都不做
*/
public class EmptyCommand implements Command{
@Override
public void execute() {
}
@Override
public void undo() {
}
}
第四步:创建遥控器
public class RemoteController {
//开关命令数组
Command[] onCommands;
Command[] offCommands;
//执行撤销命令
Command undoCommand;
public RemoteController() {
onCommands = new Command[5];
offCommands = new Command[5];
for (int i = 0; i < 5; i++) {
onCommands[i] = new EmptyCommand();
offCommands[i] = new EmptyCommand();
}
}
//给我们的按钮设置你需要的命令
public void setCommand(int no, Command onCommand, Command offCommand) {
onCommands[no] = onCommand;
offCommands[no] = offCommand;
}
//按下开按钮
public void onButtonWasPushed(int no) {
//找到你按下的开的按钮,并调用对应方法.
onCommands[no].execute();
//记录当前按钮,用于撤销.
undoCommand = onCommands[no];
}
//按下关按钮
public void offButtonWasPushed(int no) {
//找到你按下的关的按钮,并调用对应方法.
offCommands[no].execute();
//记录当前按钮,用于撤销.
undoCommand = offCommands[no];
}
//按下撤销按钮
public void undoButtonWasPushed(int no) {
undoCommand.undo();
}
}
第五步:创建测试类
public class Client {
public static void main(String[] args) {
//使用命令设计模式,完成通过遥控器,对电灯的操作
//创建电灯对象(接受者)
LightReceiver lightReceiver = new LightReceiver();
//创建电灯相关的开关命令
LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver);
LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver);
//需要一个遥控器来控制
RemoteController remoteController = new RemoteController();
//给我们的遥控器设置命令,比如 no = 0 是电灯的开和关操作.
remoteController.setCommand(0, lightOnCommand, lightOffCommand);
System.out.println("---------按下电灯的开按钮--------");
remoteController.onButtonWasPushed(0);
System.out.println("---------按下电灯的关按钮--------");
remoteController.offButtonWasPushed(0);
System.out.println("---------按下电灯的撤销按钮--------");
remoteController.undoButtonWasPushed(0);
//创建电视机对象(接受者)
TVReceiver tvReceiver = new TVReceiver();
//创建电视机相关的开关命令
TVOnCommand tvOnCommand = new TVOnCommand(tvReceiver);
TVOffCommand tvOffCommand = new TVOffCommand(tvReceiver);
//需要一个遥控器来控制
//给我们的遥控器设置命令,比如 no = 1 是电视机的开和关操作.
remoteController.setCommand(1, tvOnCommand, tvOffCommand);
System.out.println("---------按下电视机的开按钮--------");
remoteController.onButtonWasPushed(1);
System.out.println("---------按下电视机的关按钮--------");
remoteController.offButtonWasPushed(1);
System.out.println("---------按下电视机的撤销按钮--------");
remoteController.undoButtonWasPushed(1);
}
}
运行如下:
---------按下电灯的开按钮--------
调用接受者的方法...
电灯打开了...
---------按下电灯的关按钮--------
调用接受者的方法...
电灯关闭了...
---------按下电灯的撤销按钮--------
调用接受者的方法...
电灯打开了...
---------按下电视机的开按钮--------
调用接受者的方法...
电视机打开了...
---------按下电视机的关按钮--------
调用接受者的方法...
电视机关闭了...
---------按下电视机的撤销按钮--------
调用接受者的方法...
电视机打开了...
优点:
1、降低了系统耦合度。 2、新的命令可以很容易添加到系统中去。
缺点:
使用命令模式可能会导致某些系统有过多的具体命令类。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。