1.什么是命令模式
命令模式(Command
Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
何时使用:在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
如何解决:通过调用者调用接受者执行命令,顺序:调用者→命令→接受者。
关键代码:定义三个角色:1、received 真正的命令执行对象 2、Command 3、invoker 使用命令对象的入口
应用实例:struts 1 中的 action 核心控制器 ActionServlet 只有一个,相当于
Invoker,而模型层的类会随着不同的应用有不同的模型类,相当于具体的 Command。优点: 1、降低了系统耦合度。 2、新的命令可以很容易添加到系统中去。
缺点:使用命令模式可能会导致某些系统有过多的具体命令类。
使用场景:认为是命令的地方都可以使用命令模式,比如: 1、GUI 中每一个按钮都是一条命令。
2、模拟 CMD。注意事项:系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作,也可以考虑使用命令模式,见命令模式的扩展。
命令模式结构示意图:
实现:
//命令接口
public interface Command {
void ExecuteCommand();
}
步骤 2
public class BakeMutton implements Command {
private Barbeacuter barbeacuter;
public BakeMutton (Barbeacuter barbeacuter){
this.barbeacuter= barbeacuter;
}
@Override
public void ExecuteCommand() {
barbeacuter.BakeMutton();
}
}
public class BakeChickenWing implements Command {
private Barbeacuter barbeacuter;
public BakeChickenWing (Barbeacuter barbeacuter){
this.barbeacuter= barbeacuter;
}
@Override
public void ExecuteCommand() {
barbeacuter.BakeChickenWing();
}
}
步骤 3
/**
* @Author 180937
* @Date 2022/9/19 14:50
* @Version 1.7
* 烤肉串者
*/
public class Barbeacuter {
public void BakeMutton(){
System.out.println("烤肉串");
}
public void BakeChickenWing(){
System.out.println("烤鸡翅");
}
}
步骤4
/**
* @Author 180937
* @Date 2022/9/19 15:06
* @Version 1.7
*/
public class Waiter {
//private Command command;
List<Command> list = new ArrayList<Command>();
/**
* 设置命令
* @param command
*/
public void WaiterCommand(Command command){
if (command.toString()=="鸡翅没有了"){
System.out.println("鸡翅没有了,请点其他");
}else {
//把请求写入日志,后面好算账
list.add(command);
System.out.println("命令:"+command.toString()+"");
}
}
public void cancelCommand(Command command){
/**
* 取消订单
*/
list.remove(command);
System.out.println("命令:"+command.toString()+"");
}
/**
* 通知
*/
public void Notyde(){
for (Command command : list) {
command.ExecuteCommand();
}
}
}
步骤5
/**
* @Author 180937
* @Date 2022/9/19 14:41
* @Version 1.7
*/
public class CommandModel {
public static void main(String[] args) {
//命令模式:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
Barbeacuter barbeacuter = new Barbeacuter();
Command bake = new BakeChickenWing(barbeacuter);
Command bake1 = new BakeChickenWing(barbeacuter);
Command bake2 = new BakeMutton(barbeacuter);
Waiter girl = new Waiter();
girl.WaiterCommand(bake);
girl.WaiterCommand(bake1);
girl.WaiterCommand(bake2);
girl.Notyde();
//优点:第一 它能较容易地设计一个命令队列,第二,在需要的情况下,可以较容易地将命令记入日志,第三,允许接收请求的一方决定是否要否决请求
//第四,可以容易地实现对请求的撤销和重做,第五,由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易。
//还有就是命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分割开。
//还有就是如果不确定是否需要这个功能,最好还是不要实现,敏捷开发原则告诉我们,不要为代码添加基于猜测的实际不需要的功能。
//如果不清楚一个系统是否需要命令模式,一般就不要着急去实现它,事实上,在需要的时候通过重构实现这个模式并不困难,只有在真正需要如撤销和恢复等功能时,把原来的代码重构为命令模式才能有意义
}
}