Java设计模式 Design Pattern:命令模式 Command Pattern
Java设计模式 Design Pattern:命令模式 Command Pattern
目的
- Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
- 将请求封装为一个对象,从而使得客户可以使用不同的参数获得不同的请求,将请求排队或记录请求,并且支持可撤销操作.
结构
- Command : declares an interface for executing an operation.
- Command : 声明一个所要执行操作的接口
- ConcreteCommand : defines a binding between a Receiver object and an action. implements Execute by invoking the corresponding operation(s) on Receiver.
- ConcreteCommand : 定义和Receiver对象之间的绑定.通过调用Receiver相应的操作实现Execute方法.
- Client : creates a ConcreteCommand object and sets its receiver.
- Client : 创建一个ConcreteCommand对象并设置它的receiver
- Invoker : asks the command to carry out the request.
- Invoker : 调用command来实施请求
- Receiver : knows how to perform the operations associated with carrying out a request. Any class may serve as a Receiver.
- Receiver : 了解怎样实施和请求相关的操作. 任何一个类都可以作为Receiver
交互
- The client creates a ConcreteCommand object and specifies its receiver.
- 客户创建一个ConcreteCommand对象并制定它的的receiver对象
- An Invoker object stores the ConcreteCommand object.
- 一个Invoker对象存储一个ConcreteCommand对象
- The invoker issues a request by calling Execute on the command. When commands are undoable, ConcreteCommand stores state for undoing the command prior to invoking Execute.
- Invoker通过执行command对象的Execute方法来发出请求.当命令是可撤销的时, ConcreteCommand在调用Execute方法之前储存命令的状态以保证可以执行撤销操作.
- The ConcreteCommand object invokes operations on its receiver to carry out the request.
- ConcreteCommand对象调用它的receiver上的操作来完成请求
应用场景
- parameterize objects by an action to perform, as MenuItem objects did above. You can express such parameterization in a procedural language with a callback function, that is, a function that's registered somewhere to be called at a later point. Commands are an object-oriented replacement for callbacks.
- 参数化对象要实现的操作,像上述的菜单对象一样.在一个过程式语言中你可以用回调函数的方式来表达这样的一个参数化.回调函数是一个在某一个位置注册,然后在后面的一个时机被调用.命令是回调函数的一个面向对象的替代品.
- specify, queue, and execute requests at different times. A Command object can have a lifetime independent of the original request. If the receiver of a request can be represented in an address space-independent way, then you can transfer a command object for the request to a different process and fulfill the request there.
- 在不同的时机订制,排队和执行请求.如果请求的接收器可以用一个地址空间独立的方式来表示,你就可以为请求传递一个命令对象来请求一个不同的处理过程来在那实现一个请求.
- support undo. The Command's Execute operation can store state for reversing its effects in the command itself. The Command interface must have an added Unexecute operation that reverses the effects of a previous call to Execute. Executed commands are stored in a history list. Unlimited-level undo and redo is achieved by traversing this list backwards and forwards calling Unexecute and Execute, espectively.
- 支持撤销. Command的Execute方法可以存储状态来反向命令自身的效果.命令对象必须增加一个Unexecute操作来反向之前调用Execute产生的效果.执行的命令被存储在一个历史列表中. 无次数限制的撤销和重做是通过列表的向前和向后运动来相应的调用Unexecute和Execute方法来实现的.
- support logging changes so that they can be reapplied in case of a system crash. By augmenting the Command interface with load and store operations, you can keep a persistent log of changes. Recovering from a crash involves reloading logged commands from disk and reexecuting them with the Execute operation.
- 支持对变更的日志操作这样当系统崩溃时他们可以被重新应用.为Command接口增加load和store操作,你可以连续的记录变更.从一个系统崩溃中恢复可以通过冲硬盘重新加载记录的命令并且使用Execute操作来重新执行他们来完成.
作用效果
- Command decouples the object that invokes the operation from the one that knows how to perform it.
- Command将调用操作的对象和知道如何实施操作的对象进行了解耦.
- Commands are first-class objects. They can be manipulated and extended like any other object.
- Commands是一个类对象.他们可以像其他对象一样被操作和扩展.
- You can assemble commands into a composite command. An example is the MacroCommand class described earlier.
- 你可以将命令组合成一个复合命令.例如前面的MacroCommand类描述的那样.
- It's easy to add new Commands, because you don't have to change existing classes.
- 增加一个命令很容易,因为你不需要去改变已经存在的类.
示例:
参考:
http://en.wikipedia.org/wiki/Command_pattern
/* The Invoker class */
public class Switch {
private PressSwitch flipUpCommand;
private PressSwitch flipDownCommand;
public Switch(PressSwitch flipUpCmd, PressSwitch flipDownCmd) {
this.flipUpCommand = flipUpCmd;
this.flipDownCommand = flipDownCmd;
}
public void flipUp() {
flipUpCommand.execute();
}
public void flipDown() {
flipDownCommand.execute();
}
}
/* The Receiver class */
public class Light {
public Light() { }
public void turnOn() {
System.out.println("The light is on");
}
public void turnOff() {
System.out.println("The light is off");
}
}
/* The Command interface */
public interface PressSwitch {
void execute();
}
/* The Command for turning on the light */
public class FlipUpCommand implements PressSwitch {
private Light theLight;
public FlipUpCommand(Light light) {
this.theLight=light;
}
public void execute(){
theLight.turnOn();
}
}
/* The Command for turning off the light */
public class FlipDownCommand implements PressSwitch {
private Light theLight;
public FlipDownCommand(Light light) {
this.theLight=light;
}
public void execute() {
theLight.turnOff();
}
}
/* The test class or client */
public class PressSwitch {
public static void main(String[] args) {
Light lamp = new Light();
PressSwitch switchUp = new FlipUpCommand(lamp);
PressSwitch switchDown = new FlipDownCommand(lamp);
// See criticism of this model above:
// The switch itself should not be aware of lamp details (switchUp, switchDown)
// either directly or indirectly
Switch s = new Switch(switchUp,switchDown);
try {
if (args[0].equalsIgnoreCase("ON")) {
s.flipUp();
} else if (args[0].equalsIgnoreCase("OFF")) {
s.flipDown();
} else {
System.out.println("Argument /"ON/" or /"OFF/" is required.");
}
} catch (Exception e){
System.out.println("Arguments required.");
}
}
}