天天看点

Java设计模式之命令模式

命令模式定义:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持撤销的操作。

通常一个命令对象就是要执行的一个命令操作,实现了共同的接口,一个命令对象通过在特定的接受者上绑定一组动作来封装一个请求。一般命令对象将所要操作的动作和接受者绑定在里面,通过提供给外部一个execute()方法来触发所需要的操作。

命令模式实现了“命令的调用者”和“命令的接受者”之间的解耦,由于命令对象里面已经绑定了所要操作的接受者以及动作,而调用者只管负责调用相应的命令对象来完成命令所包含的动作,调用者根本不知道它所操作的是哪一个接受者,只知道它要做的是何种操作而已。

其实命令模式如同其他设计模式一样——通过将你的的请求和你的处理之间,加上了一个中间人的角色,来达到分离耦合的目的。通过对中间人角色的特殊设计来形成不同的模式。当然命令模式就是一种特殊设计的结果。

它的类图如下:

通常它的组成包括如下:

1) 命令角色(Command):声明执行操作的接口。由接口或者抽象类来实现。

2) 具体命令角色(Concrete Command):将一个接收者对象绑定于一个动作,调用接收者相应的操作,以实现命令角色声明的执行操作的接口。

3) 客户角色(Client):创建一个具体命令对象(并可以设定它的接收者)。

4) 调用者角色(Invoker):调用命令对象执行这个请求。

5) 接收者角色(Receiver):知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。

一般来说具体命令角色仅仅包含着一种命令,如果想要一个命令包含多种命令那么就可以利用宏命令,在一个具体命令角色中提前设置好各种具体命令角色来处理。

命令模式一般具有撤销操作,一般就是在调用者里面做好预处理,在每一个具体命令角色中设置好撤销操作的执行动作。

命令模式的优点:

1) 命令模式将调用操作的请求对象与执行该操作的接收对象解耦。

2) 具体命令角色可以被不同的请求者角色重用。

3) 可将多个命令装配成一个复合命令,即宏命令。

4) 增加新的具体命令角色很容易,因为这无需改变已有的类。

命令模式的应用场景:

1) 需要抽象出待执行的动作,然后以参数的形式提供出来——类似于过程设计中的回调机制。而命令模式正是回调机制的一个面向对象的替代品。

2) 在不同的时刻指定、排列和执行请求。

3) 需要支持取消操作。

4) 支持修改日志功能。这样当系统崩溃时,这些修改可以被重做一遍。

5) 需要支持事务操作。

命令模式的要点:

1)在被解耦的两者之间即接受者和调用者通过命令对象来沟通的。

2)调用者通过调用命令对象的execute()发出请求,这就会促使接受者开始执行命令的动作。

举例说明:

一个控制器,可以控制许多个设备,通过向设备发出各种命令来执行。

命令角色接口:

package com.whut.command;

//各种命令的基类

publicinterface Command {

void execute();

void undo();

}

具体命令角色:

publicclass LightOffCommand implements Command {

Light light;

public LightOffCommand(Light light)

{

this.light=light;

@Override

publicvoid execute() {

// TODO Auto-generated method stub

light.off();

publicvoid undo() {

light.on();

调用者角色:

publicclass RemoteControl {

private Command[] onCommands;

private Command[] offCommands;

private Command undoCommand;

public RemoteControl()

onCommands=new Command[7];

offCommands=new Command[7];

undoCommand=new NoCommand();

for(int i=0;i<7;i++)

onCommands[i]=new NoCommand();

offCommands[i]=new NoCommand();

publicvoid setCommand(int slot,Command onCommand,Command offCommand)

onCommands[slot]=onCommand;

offCommands[slot]=offCommand;

publicvoid onButtonWasPressed(int slot)

onCommands[slot].execute();

undoCommand=onCommands[slot];

publicvoid offButtonWasPressed(int slot)

offCommands[slot].execute();

undoCommand=offCommands[slot];

publicvoid undoButtonWasPressed()

undoCommand.undo();

public String toString()

StringBuffer stringBuff=new StringBuffer();

stringBuff.append("\n------Remote Control-------------\n");

stringBuff.append("[slot "+i+" ]"+onCommands[i].getClass().getName()

+" "+offCommands[i].getClass().getName()+"\n");

return stringBuff.toString();

接受者角色:

//各种接受者

publicclass Light {

private String lightType;

public Light(String light)

this.lightType=light;

publicvoid on()

System.out.println("The "+lightType+" is on...");

publicvoid off()

System.out.println("The "+lightType+" is off...");

客户角色:

publicclass RemoteLoader {

publicstaticvoid main(String[] args)

RemoteControl remote=new RemoteControl();

Light livingRoomLight=new Light("Living Room");

LightOnCommand livingRoomOn=new LightOnCommand(livingRoomLight);

LightOffCommand livingRoomOff=new LightOffCommand(livingRoomLight);

remote.setCommand(0, livingRoomOn, livingRoomOff);

remote.onButtonWasPressed(0);

remote.offButtonWasPressed(0);

System.out.println(remote);

remote.undoButtonWasPressed();

本文转自 zhao_xiao_long 51CTO博客,原文链接:http://blog.51cto.com/computerdragon/1156583