一、什么是命令模式
什么是命令模式?就是字面理解,下命令,但是还不能这么快下定义,可以举一个例子来说明一下。好多电影里面经常会有一个神秘的杀手组织,他们只管要钱和目标。不管是谁的委托,经常有个大富豪,说“为了确保万无一失,无论多少钱,我要求派出江湖第一杀手”,他们可是把命令模式玩的飞起。就好像《这个杀手不太冷》中主角杀手莱昂接受任务和执行任务的过程。
在电影中,莱昂(里昂)是一个职业杀手,他通过中间人接受任务,并执行任务。这个过程可以类比为命令模式,其中莱昂是“接收者”,中间人是“调用者”,而任务本身是“命令”。通过《这个杀手不太冷》中的场景,我们可以清晰地看到命令模式的核心优势。命令模式通过将请求封装为对象,使得请求的发起者和执行者之间解耦,提高了系统的灵活性和可扩展性。这种模式特别适用于需要动态执行命令(封装的请求)的场景。命令模式(Command Pattern)是一种行为型设计模式,它将请求封装为一个对象,从而使用户可以用不同的请求对客户进行参数化。
二、为什么用命令模式
-
解耦客户端和接收者:客户端(客户)不需要直接调用接收者(杀手)的业务方法,而是通过命令对象间接调用。杀手组织只接受命令,而不管命令的具体内容或发起者是谁。
-
支持可撤销操作:命令模式可以轻松实现命令的撤销和重做功能。具体命令类可以保存操作前的状态,以便在需要时恢复。
-
支持命令排队和日志记录:命令对象可以被存储在队列中,支持命令的排队执行。同时,命令对象可以被记录在日志中,便于后续的审计和恢复。
-
扩展性:命令模式支持动态添加新的命令,而不需要修改现有的代码。新的命令只需要实现命令接口即可。
三、命令模式示例
代码示例以及命令模式的角色解析
-
Command(命令接口,定义任务统一行为):定义了执行操作的接口,所有具体命令类都实现这个接口。
public interface Command { void execute(); }
-
ConcreteCommand(具体命令类,具体的任务):实现了命令接口,具体执行操作。它通常持有一个接收者对象,并调用接收者的业务方法来完成操作。
public class KillCommand implements Command { private Hitman hitman; private String target; public KillCommand(Hitman hitman, String target) { this.hitman = hitman; this.target = target; } @Override public void execute() { hitman.kill(target); } }
-
Receiver(接收者,杀手):实际执行操作的对象。具体命令类会调用接收者的业务方法来完成操作。
public class Hitman { public void kill(String target) { System.out.println("杀手莱恩准备执行刺杀任务,任务目标: " + target); } }
-
Invoker(调用者,杀手组织中间人):负责调用命令对象的执行方法。它通常持有一个命令对象,并在适当的时候调用命令对象的执行方法。
public class Middleman { private Command command; public void setCommand(Command command) { this.command = command; } public void executeCommand() { command.execute(); } }
-
Client(客户端):创建具体命令对象,并将其与接收者关联。客户端将命令对象传递给调用者,调用者在适当的时候执行命令。
public class Main { public static void main(String[] args) { // 创建接收者(杀手莱昂) Hitman hitman = new Hitman(); // 创建具体命令对象(任务) Command killCommand = new KillCommand(hitman, "小女孩"); // 创建调用者(中间人) Middleman middleman = new Middleman(); // 设置命令并执行 middleman.setCommand(killCommand); middleman.executeCommand(); } } //输出 杀手莱恩准备执行刺杀任务,任务目标: 小女孩