《大话设计模式》读书笔记 - 命令模式
1、定义
将一个请求封装为一个对象,从而可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作
2、模型图
在该类图中,我们看到四个角色:
- Command:需要执行的所有命令都在这里声明,可以是接口或者抽象类
- ConcreteCommand:将一个接收者对象绑定于一个动作,调用接收者相应的操作,以实现Execute
- Receiver接受者角色:该角色就是干活的角色,命令传递到这里是应该被执行的
- Invoker调用者角色:接收到命令,并执行命令
3、应用场景
在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
4、举例
下面一个烧烤店的例子,帮助理解命令设计模式
烤羊肉串和烤鸡翅是烧烤师傅具体实现的,本来是两个方法,现在却变成两个类烤羊肉串类和烤鸡翅类并在里面调用烧烤师傅的烧烤命令
Barbecuer是表示烧烤师傅
public class Barbecuer {
/**
* 烤羊肉串
*/
public void BakeMutton(){
System.out.println("烤羊肉串");
}
/**
* 烤鸡翅
*/
public void BakkeChickenWing(){
System.out.println("烤鸡翅");
}
}
Command 用来声明执行操作的接口
public interface Command {
/**
* 具体的执行方法
*/
void excute();
}
BakeChickenWingCommand 烤鸡翅类
public class BakeChickenWingCommand implements Command {
public Barbecuer barbecuer;
public BakeChickenWingCommand(Barbecuer barbecuer) {
this.barbecuer = barbecuer;
}
public void excute() {
this.barbecuer.BakkeChickenWing();
}
}
BakeMuttonCommand 烤羊肉串类
public class BakeMuttonCommand implements Command {
public Barbecuer barbecuer;
public BakeMuttonCommand(Barbecuer barbecuer) {
this.barbecuer = barbecuer;
}
public void excute() {
barbecuer.BakeMutton();
}
}
Waiter 服务员小姐姐,给客户下单,修改订单,通知后厨。。。
public class Waiter {
private List<Command> command = new ArrayList<Command>();
/**
* 新增订单
*
* @param command
*/
public void addOrder(Command command) {
this.command.add(command);
}
/**
* 修改订单
* @param command
*/
public void delOrder(Command command){
this.command.remove(command);
}
/**
* 通知后厨烤肉
*/
public void msg() {
for (Command com : command) {
com.excute();
}
}
}
Main 模拟客户下单场景
public class Main {
public static void main(String[] args) {
//创建烤肉师傅对象
Barbecuer barbecuer = new Barbecuer();
//创建烤鸡翅对象
BakeChickenWingCommand chickenWingCommand = new BakeChickenWingCommand(barbecuer);
//创建烤羊肉串对象
BakeMuttonCommand muttonCommand = new BakeMuttonCommand(barbecuer);
//创建服务员小姐姐对象
Waiter girl = new Waiter();
//客户下单
girl.addOrder(chickenWingCommand);
girl.addOrder(muttonCommand);
girl.msg();
}
}
总结:
优点:
- 类间解耦:调用者角色与接收者角色之间没有任何依赖关系,调用者实现功能时只需调用Command 抽象类的execute方法就可以,不需要了解到底是哪个接收者执行。
- 可扩展性:Command的子类可以非常容易地扩展,而调用者Invoker和高层次的模块Client不产生严 重的代码耦合。
- 命令模式结合其他模式会更优秀:命令模式可以结合责任链模式,实现命令族解析任务;结合模板方法模式,则可以减少 Command子类的膨胀问题。
缺点:
命令模式也是有缺点的,请看Command的子类:如果有N个命令,问题就出来了,Command的子类就可不是几个,而是N个,这个类膨胀得非常大,这个就需要读者在项 目中慎重考虑使用。