命令模式(Command) ,是行为设计模式的一种。Command模式通过被称为Command的类封装了对目标对象的调用行为以及调用参数。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
解决问题:
在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
应用场景:
在面向对象的程序设计中,一个对象调用另一个对象,一般情况下的调用过程是:创建目标对象实例;设置调用参数;调用目标对象的方法。
在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
- 整个调用过程比较繁杂,或者存在多处这种调用。这时,使用Command类对该调用加以封装,便于功能的再利用。
- 调用前后需要对调用参数进行某些处理。
- 调用前后需要进行某些额外处理,比如日志,缓存,记录历史操作等
应用实例:
struts 1 中的 action 核心控制器 ActionServlet 只有一个,相当于 Invoker,而模型层的类会随着不同的应用有不同的模型类,相当于具体的Command。
命令模式UML图:
角色和职责:
Command:ommand抽象类。
ConcreteCommand:command的具体实现类,需要执行的所有命令都在这里声明。
Receiver: 调用的目标对象,真正的命令执行对象,命令传到这里应该被执行。
Invorker: invorker执行Command对象,使用命令对象的入口实现代码示例:
/**
* 命令接收者Receiver类
* 小商贩
*/
public class Peddler {
//卖苹果
public void sailApple(){
System.out.println("卖苹果");
}
//卖香蕉
public void sailBanana(){
System.out.println("卖香蕉");
}
}
/**
* Command抽象类
*/
public abstract class Command {
private Peddler peddler;
public Command(Peddler peddler){
this.setPeddler(peddler);
}
public Peddler getPeddler() {
return peddler;
}
public void setPeddler(Peddler peddler) {
this.peddler = peddler;
}
public abstract void sail();
}
public class BananaCommand extends Command {
public BananaCommand(Peddler peddler) {
super(peddler);
}
@Override
public void sail() {
this.getPeddler().sailBanana();
}
}
public class AppleCommand extends Command {
public AppleCommand(Peddler peddler) {
super(peddler);
}
@Override
public void sail() {
this.getPeddler().sailApple();
}
}
/**
* 调用者invoker类
*/
public class Waiter {
private List<Command> commands = new ArrayList<Command>();
public void setOrder(Command command){
commands.add(command);
}
public void removeOrder(Command command){
commands.remove(command);
}
public void sail(){
for(Command command : commands){
command.sail();
}
}
}
public class MainClass {
public static void main(String[] args) {
//创建Receiver
Peddler peddler = new Peddler();
Command appleCommand = new AppleCommand(peddler);
Command bananaCommand = new BananaCommand(peddler);
Waiter waiter = new Waiter();
//下订单
waiter.setOrder(appleCommand);
waiter.setOrder(bananaCommand);
//移除订单某项
// waiter.removeOrder(appleCommand);
waiter.sail();
}
}
优点:
1、降低了系统耦合度。类间解耦:调用者角色与接收者角色之间没有任何依赖关系,调用者实现功能时只需调用Command 抽象类的方法就可以,不需要了解到底是哪个接收者执行。
2、可扩展性:Command的子类可以非常容易地扩展,而调用者Invoker和高层次的模块Client不产生严重的代码耦合。
缺点:
使用命令模式可能会导致某些系统有过多的具体命令类。