命令模式
将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
我们知道一个命令各对象通过在特定接收者上绑定一组动作来封装一个请求。要达到这一点,命令对象将动作和接收者包进对象中。这个对象只暴露出一个execute()方法,当此方法被调用时,接收者就会进行这些动作。从外面来看,其他对象不知道究竟哪个接收者进行了哪些动作,只知道如果调用execute()方法,请求的目的就能达到。
具体例子
所有命令对象实现相同的接口:Command.java
[java]view plaincopyprint?
1. package com.designpattern.command;
2.
3. public interface Command {
4. public void execute();
5. public void undo();
6.
7. }
package com.designpattern.command;
public interface Command {
public void execute();
public void undo();
}
Light.java
[java]view plaincopyprint?
1. package com.designpattern.command;
2.
3. public class Light {
4. private boolean on = false;
5.
6. public void on() {
7. this.on = true;
8. }
9.
10. public void off() {
11. this.on = false;
12. }
13.
14. public String getStatus() {
15. if (on) {
16. return "ON";
17. } else {
18. return "OFF";
19. }
20. }
21. }
package com.designpattern.command;
public class Light {
private boolean on = false;
public void on() {
this.on = true;
}
public void off() {
this.on = false;
}
public String getStatus() {
if (on) {
return "ON";
} else {
return "OFF";
}
}
}
开灯的命令 对象:OnCommand.java,定义了动作和接收者之间的绑定关系。调用者只要调用execute()方法就可以发出请求,然后调用接收者的一个或多个动作。
[java]view plaincopyprint?
1. package com.designpattern.command;
2.
3. public class OnCommand implements Command {
4. private Light light;
5.
6. public OnCommand(Light l) {
7. this.light = l;
8. }
9.
10. @Override
11. public void execute() {
12. light.on();
13. }
14.
15. @Override
16. public void undo() {
17. light.off();
18. System.out.println("The light is off!");
19. }
20.
21. }
package com.designpattern.command;
public class OnCommand implements Command {
private Light light;
public OnCommand(Light l) {
this.light = l;
}
@Override
public void execute() {
light.on();
}
@Override
public void undo() {
light.off();
System.out.println("The light is off!");
}
}
关灯的命令对象:OffCommand.java
[java]view plaincopyprint?
1. package com.designpattern.command;
2.
3. public class OffCommand implements Command {
4.
5. private Light light;
6.
7. public OffCommand(Light l){
8. this.light = l;
9. }
10.
11. @Override
12. public void execute() {
13. light.off();
14. }
15.
16. @Override
17. public void undo() {
18. light.on();
19. System.out.println("The light is on!");
20. }
21.
22. }
package com.designpattern.command;
public class OffCommand implements Command {
private Light light;
public OffCommand(Light l){
this.light = l;
}
@Override
public void execute() {
light.off();
}
@Override
public void undo() {
light.on();
System.out.println("The light is on!");
}
}
空命令:NoCommand.java,将处理null的责任转移给空命令对象,当调用它的execute()方法时,这个对象什么事情都不做。
[java]view plaincopyprint?
1. package com.designpattern.command;
2.
3. public class NoCommand implements Command {
4.
5. @Override
6. public void execute() {
7. // TODO Auto-generated method stub
8.
9. }
10.
11. @Override
12. public void undo() {
13. // TODO Auto-generated method stub
14.
15. }
16.
17. }
package com.designpattern.command;
public class NoCommand implements Command {
@Override
public void execute() {
// TODO Auto-generated method stub
}
@Override
public void undo() {
// TODO Auto-generated method stub
}
}
调用者:Invoker.java,持有一个命令对象,并在某个时间点调用命令对象的execute()方法,将请求付诸实行。
[java]view plaincopyprint?
1. package com.designpattern.command;
2.
3. //调用者
4. public class Invoker {
5.
6. private Command command;
7.
8. private Command undoCommand;
9.
10. public Invoker() {
11. command = new NoCommand();
12. undoCommand = new NoCommand();
13. }
14.
15. public void setCommand(Command c) {
16. this.command = c;
17. }
18.
19. public void pressButton() {
20. this.command.execute();
21. undoCommand = command;
22. }
23.
24. public void undoPress() {
25. undoCommand.undo();
26. }
27. }
package com.designpattern.command;
//调用者
public class Invoker {
private Command command;
private Command undoCommand;
public Invoker() {
command = new NoCommand();
undoCommand = new NoCommand();
}
public void setCommand(Command c) {
this.command = c;
}
public void pressButton() {
this.command.execute();
undoCommand = command;
}
public void undoPress() {
undoCommand.undo();
}
}
测试类:Test.java,负责创建一个具体的命令,并设置其接收者。
[java]view plaincopyprint?
1. package com.designpattern.command;
2.
3. public class Test {
4.
5. /**
6. * @param args
7. */
8. public static void main(String[] args) {
9.
10. Light light = new Light();
11.
12. Command on = new OnCommand(light);//具体命令,light为接收者
13. Command off = new OffCommand(light);
14.
15. Invoker invoker = new Invoker();
16. invoker.setCommand(on);
17. invoker.pressButton();
18. invoker.undoPress();
19.
20. System.out.println("Light "+light.getStatus());
21. }
22.
23. }
package com.designpattern.command;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
Light light = new Light();
Command on = new OnCommand(light);//具体命令,light为接收者
Command off = new OffCommand(light);
Invoker invoker = new Invoker();
invoker.setCommand(on);
invoker.pressButton();
invoker.undoPress();
System.out.println("Light "+light.getStatus());
}
}
要点总结
1、命令模式将发出请求的对象和执行请求的对象解耦。
2、在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接收者和一个或一组动作。
3、调用者通过调用命令对象的execute()方法发出请求,这会使得接收者的动作被调用。
4、调用者可以接收命令当做参数,甚至在运行时动态地进行。
5、命令可以支持撤销,做法是实现一个undo()方法来回到execute()被执行前的状态。
6、宏命令是命令的一种简单的延伸,允许调用多个命令。宏方法也可以支持撤销。
7、实际操作时,很常见使用“聪明”命令对象,也就是直接实现了请求,而不是将工作委托给接收者。
8、命令也可以用来实现日志和事务系统。
活在当下,别在怀念过去或者憧憬未来中浪费掉你现在的生活。