目录
1.命令模式的概念
将请求封装成一个对象,这样就可以使用不同的请求来对客户端进行参数化,对请求进行排队或记录日志,还支持可撤销的操作
2.命令模式的结构图
- Invoker是调用者角色。
- Command:是命令角色,需要执行的所有命令都在这里,可以是接口或抽象类。
- Receiver:接受者角色,知道如何实施和执行一个请求相关的操作。
- ConcreteCommand:将一个接受者对象与一个动作绑定,调用接受者相应的操作,实现 execute。
3. 练习的例子
抽象的命令类(Command):
/**
*
* 抽象的命令类
*/
@Data
abstract class Command {
/**
* 命令类维护了烤肉的厨师
*/
private Barbecuer barbecuer;
public Command(Barbecuer barbecuer){
this.barbecuer = barbecuer;
}
/**
* 执行命令的操作
*/
public abstract void excuteCommand();
}
烤鸡翅的命令(ConcreteCommand):
/**
* 烤鸡翅的命令类
*/
public class MakeChickenWingCommand extends Command{
public MakeChickenWingCommand(Barbecuer barbecuer) {
super(barbecuer);
}
/**
* 执行烤鸡翅的命令
*/
@Override
public void excuteCommand() {
getBarbecuer().makeChickenWing();
}
}
烤羊肉的命令(ConcreteCommand):
/**
* 烤羊肉的命令类
*/
public class MakeMuttonCommand extends Command{
public MakeMuttonCommand(Barbecuer barbecuer) {
super(barbecuer);
}
/**
* 执行烤羊肉的命令
*/
@Override
public void excuteCommand() {
getBarbecuer().makeMutton();
}
}
服务员类(Invoker) :
/**
* 服务员类 对命令对象进行排队,记录日志等操作
*/
@Data
@Slf4j
public class Waiter {
private Command command;
/**
* 用来记录命令的账本
*/
private List<Command> list = new ArrayList<>();
/**
* 对命令对象进行排队并记录日志
* @param command
*/
public void setCommand(Command command){
if (command instanceof MakeChickenWingCommand) {
System.out.println("鸡翅考完啦,换个吃吃吧!");
}else {
list.add(command);
log.info("增加了一个羊肉串");
log.info("时间:" + LocalDateTime.now());
}
}
/**
* 对命令对象进行撤销操作
* @param command
*/
public void cancelOrder(Command command){
list.remove(command);
log.info("去掉了一个羊肉串");
log.info("时间:" + LocalDateTime.now());
}
/**
* 执行命令
*/
public void notyfied(){
for (Command command:list) {
command.excuteCommand();
}
}
}
烤肉的厨师类(receiver):
/**
* 烤肉的厨师
*/
public class Barbecuer {
public void makeMutton(){
System.out.println("烤羊肉串啦!");
}
public void makeChickenWing(){
System.out.println("烤鸡翅啦!");
}
}
测试类:
public class Test {
public static void main(String[] args) {
//一个厨师
Barbecuer barbecuer = new Barbecuer();
//一个鸡翅,三个羊肉串
MakeChickenWingCommand makeChickenWingCommand1 = new MakeChickenWingCommand(barbecuer);
MakeMuttonCommand makeMuttonCommand1 = new MakeMuttonCommand(barbecuer);
MakeMuttonCommand makeMuttonCommand2 = new MakeMuttonCommand(barbecuer);
MakeMuttonCommand makeMuttonCommand3 = new MakeMuttonCommand(barbecuer);
//服务员记录订单
Waiter waiter = new Waiter();
waiter.setCommand(makeChickenWingCommand1);
waiter.setCommand(makeMuttonCommand1);
waiter.setCommand(makeMuttonCommand2);
waiter.setCommand(makeMuttonCommand3);
//服务员退菜
System.out.println("服务员,点多啦,最后点的羊肉串不要了!");
waiter.cancelOrder(makeMuttonCommand3);
//让厨师烤串
waiter.notyfied();
}
}
控制台:
4.示例的结构图:
5.总结:
命令模式的优点:
- 它能较容易地设计一个命令队列;
- 在需要的情况下,可以较容易地将命令记入日志;
- 允许接收请求的一方决定是否要否决请求;
- 可以容易地实现对请求的撤销和重做;
- 由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易;
- 最关键的优点就是命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分割开;
个人理解:
- 一个命令对应一个receiver类的方法
缺点:
- 可能导致某些系统有过多的具体命令类,增加了系统的复杂度