设计模式-命令模式
命令模式(Command Pattern)
命令模式(Command Pattern):将请求封装成对象,以便使用不同的请求、日志、队列等来参数化其他对象。命令模式也支持撤销操作。
命令模式结构:
Command:
定义命令的接口,声明执行的方法。
ConcreteCommand:
具体的命令, 实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
Receiver:
接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
Invoker:
要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
Client:
创建具体的命令对象,并且设置命令对象的接收者。注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者,或许,把这个Client称为装配者会更好理解,因为真正使用命令的客户端是从Invoker来触发执行。
//Receiver:接收者,真正执行命令的对象。 public class Light{ public void on(){System.out.println("开灯");} public void off(){System.out.println(" 关灯");} } //Receiver:接收者,真正执行命令的对象。 public class TV{ public void on(){System.out.println("开电视");} public void off(){System.out.println(" 关电视");} }
//Command:定义命令的接口,声明执行的方法。 public interface Command{ public void execute(); } //ConcreteCommand:具体的命令,实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。 public class NoCommand implements Command{ @Override public void execute() {System.out.println("还没有为开关绑定操作");} } //ConcreteCommand:具体的命令,实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。 public class LightOnCommand implements Command{ private Light light; public LightOnCommand(Light light) {this.light = light;} @Override public void execute() { light.on();} } //ConcreteCommand:具体的命令,实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。 public class LightOffCommand implements Command{ private Light light; public LightOffCommand(Light light) {this.light = light;} @Override public void execute() { light.off();} } //ConcreteCommand:具体的命令,实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。 public class TVOnCommand implements Command{ private TV tv; public TVOnCommand(TV tv) { this.tv = tv;} @Override public void execute() {tv.on();} } //ConcreteCommand:具体的命令,实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。 public class TVOffCommand implements Command{ private TV tv; public TVOffCommand(TV tv) {this.tv = tv;} @Override public void execute() {tv.off();} }
//Invoker:要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。 public class Invoker{ private Command[] onCommands; private Command[] offCommands; public Invoker() { onCommands = new Command[7]; offCommands = new Command[7]; //初始化 Command noCommand = new NoCommand(); for (int i=0; i<7;i++){ onCommands[i] = noCommand; offCommands[i] = noCommand; } } public void setCommand(int slot,Command onCommand,Command offCommand){ onCommands[slot] = onCommand; offCommands[slot] = offCommand; } public void onButtonPush(int slot){ onCommands[slot].execute(); } public void offButtonPush(int slot){ offCommands[slot].execute(); } }
//Client:创建具体的命令对象,并且设置命令对象的接收者。 // 注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者,或许,把这个Client称为装配者会更好理解,因为真正使用命令的客户端是从Invoker来触发执行。 public class Client{ public static void main(String[] args){ Invoker invoker = new Invoker(); Light light = new Light(); LightOnCommand lightOnCommand = new LightOnCommand(light); LightOffCommand lightOffCommand = new LightOffCommand(light); TV tv = new TV(); TVOnCommand tvOnCommand = new TVOnCommand(tv); TVOffCommand tvOffCommand = new TVOffCommand(tv); invoker.setCommand(0,lightOnCommand,lightOffCommand); invoker.setCommand(1,tvOnCommand,tvOffCommand); invoker.onButtonPush(0); invoker.offButtonPush(0); } }
优点:
1、降低了系统耦合度。
2、新的命令可以很容易添加到系统中去。
缺点:
1、使用命令模式可能会导致某些系统有过多的具体命令类。
应用场景:
1、命令和实际的执行者分离,实际的操作都是通过invoker以及receiver去执行的
2、屏蔽了底层的复杂实现,对外提供了统一的表现
3、可以记录操作的历史记录
4、拓展性好,一方面,可以很方便地添加新的命令,如在word中添加插入html功能;另一方面,也可以把命令迁移到另一种场景下,如把word中的命令迁移到excel中
5、用户使用上,用户通过组合一些命令,可以实现宏的功能,效率更高