一、行为型模式在面向对象的世界里如何优雅地组织对象间的交互、分配职责是每一位开发者都会反复思考的问题。直接硬编码交互逻辑固然简单但当业务复杂度上升、对象协作关系变得错综复杂时这种方式就会让代码变得僵化、难以扩展。行为型设计模式正是为了解决这一痛点而诞生的一套思想体系。它们关注如何定义对象之间的通信方式和职责分配通过命令、迭代、观察者、策略等手段让对象间的协作更具灵活性、可复用性和可维护性。在 Java 开发中行为型模式主要包含以下 11 种经典实现模板方法模式 (Template Method)定义一个操作中的算法的骨架而将一些步骤延迟到子类中使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。Java 设计模式・模板方法模式篇从思想到代码实现-CSDN博客策略模式 (Strategy)定义一系列的算法把它们一个个封装起来并且使它们可相互替换让算法独立于使用它的客户而变化。Java 设计模式・策略模式篇从思想到代码实现-CSDN博客命令模式 (Command)将一个请求封装为一个对象从而使你可以用不同的请求对客户进行参数化支持可撤销操作。责任链模式 (Chain of Responsibility)将请求的发送者和接收者解耦使多个对象都有机会处理这个请求形成一条处理链。Java 设计模式・责任链模式篇从思想到代码实现-CSDN博客状态模式 (State)允许一个对象在其内部状态改变时改变它的行为对象看起来似乎修改了它的类。Java 设计模式・状态模式篇从思想到代码实现-CSDN博客观察者模式 (Observer)定义对象间的一种一对多的依赖关系当一个对象的状态发生改变时所有依赖它的对象都得到通知并被自动更新。Java 设计模式・观察者模式篇从思想到代码实现-CSDN博客中介者模式 (Mediator)用一个中介对象来封装一系列的对象交互使各对象不需要显式地相互引用从而降低耦合。Java 设计模式・中介者模式篇从思想到代码实现-CSDN博客迭代器模式 (Iterator)提供一种方法顺序访问一个聚合对象中的各个元素而又不暴露其内部的表示。Java 设计模式・迭代器模式篇从思想到代码实现-CSDN博客访问者模式 (Visitor)表示一个作用于某对象结构中的各元素的操作它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。Java 设计模式・访问者模式篇从思想到代码实现-CSDN博客备忘录模式 (Memento)在不破坏封装性的前提下捕获一个对象的内部状态并在该对象之外保存这个状态以便以后恢复。Java 设计模式・备忘录模式篇从思想到代码实现-CSDN博客解释器模式 (Interpreter)给定一个语言定义它的文法的一种表示并定义一个解释器这个解释器使用该表示来解释语言中的句子。Java 设计模式・解释器模式篇从思想到代码实现-CSDN博客二、命令模式2.1 介绍命令模式Command Pattern是一种行为型设计模式它的核心定义是将一个请求封装为一个对象从而使你可用不同的请求对客户进行参数化对请求排队或记录请求日志以及支持可撤销的操作。2.2 角色抽象命令类Command角色 定义命令的接口声明执行的方法。具体命令Concrete Command角色具体的命令实现命令接口通常会持有接收者并调用接收者的功能来完成命令要执行的操作。实现者/接收者Receiver角色 接收者真正执行命令的对象。任何类都可能成为一个接收者只要它能够实现命令要求实现的相应功能。调用者/请求者Invoker角色 要求命令对象执行请求通常会持有命令对象可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方也就是说相当于使用命令对象的入口。三、代码实现为了方便理解本文采用中文定义类名3.1 接收者public class 厨师 { // 做鱼香肉丝 public void cookYuXiangRouSi() { System.out.println(厨师鱼香肉丝制作完成); } // 做宫保鸡丁 public void cookGongBaoJiDing() { System.out.println(厨师宫保鸡丁制作完成); } }3.2 抽象命令public abstract class 点餐 { // 执行命令做菜 abstract void execute(); }3.3 具体命令public class 点餐宫保鸡丁 extends 点餐{ // 持有接收者厨师的引用 private 厨师 chef; public 点餐宫保鸡丁(厨师 chef) { this.chef chef; } Override void execute() { chef.cookGongBaoJiDing(); } }public class 点餐鱼香肉丝 extends 点餐{ // 持有接收者厨师的引用 private 厨师 chef; public 点餐鱼香肉丝(厨师 chef) { this.chef chef; } Override void execute() { chef.cookYuXiangRouSi(); } }3.4 调用者public class 服务员 { private 点餐 order; public void takeOrder(点餐 order) { this.order order; System.out.println(服务员已记录当前菜品); order.execute(); } }3.5 客户端public class 客户 { public static void main(String[] args) { 厨师 chef new 厨师(); 点餐 order1 new 点餐宫保鸡丁(chef); 点餐 order2 new 点餐鱼香肉丝(chef); 服务员 waiter new 服务员(); waiter.takeOrder(order1); waiter.takeOrder(order2); } }服务员已记录当前菜品 厨师宫保鸡丁制作完成 服务员已记录当前菜品 厨师鱼香肉丝制作完成 Process finished with exit code 0四、代码实现加上撤销4.1 接收者public class 厨师 { // 做鱼香肉丝 public void cookYuXiangRouSi() { System.out.println(厨师鱼香肉丝制作完成); } // 做宫保鸡丁 public void cookGongBaoJiDing() { System.out.println(厨师宫保鸡丁制作完成); } // 取消做菜支持撤销操作 public void cancelCook(String dishName) { System.out.println(厨师取消制作 dishName 清理食材); } }4.2 抽象命令public abstract class 点餐 { // 执行命令做菜 abstract void execute(); // 撤销命令取消做菜 abstract void undo(); }4.3 具体命令public class 点餐宫保鸡丁 extends 点餐{ // 持有接收者厨师的引用 private 厨师 chef; public 点餐宫保鸡丁(厨师 chef) { this.chef chef; } Override void execute() { chef.cookGongBaoJiDing(); } Override public void undo() { chef.cancelCook(宫保鸡丁); } }public class 点餐鱼香肉丝 extends 点餐{ // 持有接收者厨师的引用 private 厨师 chef; public 点餐鱼香肉丝(厨师 chef) { this.chef chef; } Override void execute() { chef.cookYuXiangRouSi(); } Override public void undo() { chef.cancelCook(鱼香肉丝); } }4.4 调用者public class 服务员 { private 点餐 order; public void takeOrder(点餐 order) { this.order order; System.out.println(服务员已记录当前菜品); order.execute(); } // 撤销订单支持撤销操作 public void undoOrder(点餐 order) { order.undo(); } }4.5 客户端public class 客户 { public static void main(String[] args) { 厨师 chef new 厨师(); 点餐 order1 new 点餐宫保鸡丁(chef); 点餐 order2 new 点餐鱼香肉丝(chef); 服务员 waiter new 服务员(); waiter.takeOrder(order1); waiter.takeOrder(order2); waiter.undoOrder(order2); } }服务员已记录当前菜品 厨师宫保鸡丁制作完成 服务员已记录当前菜品 厨师鱼香肉丝制作完成 厨师取消制作鱼香肉丝清理食材五、代码实现加上队列5.1 接收者抽象命令具体命令不变5.2 调用者public class 服务员 { private List点餐 orders new ArrayList(); public void takeOrder(点餐 order) { orders.add(order); System.out.println(客户点餐成功); } // 提交所有订单触发命令执行 public void submitOrders() { System.out.println(服务员开始提交所有订单给厨师...); for (点餐 order : orders) { order.execute(); // 执行每一个做菜命令 } orders.clear(); // 提交后清空订单 } // 撤销最后一个订单支持撤销操作 public void undoLastOrder() { if (!orders.isEmpty()) { 点餐 lastOrder orders.remove(orders.size() - 1); System.out.println(服务员撤销最后一个订单...); lastOrder.undo(); } else { System.out.println(服务员暂无可撤销的订单); } } }5.3 客户端public class 客户 { public static void main(String[] args) { 厨师 chef new 厨师(); 点餐 order1 new 点餐宫保鸡丁(chef); 点餐 order2 new 点餐鱼香肉丝(chef); 服务员 waiter new 服务员(); waiter.takeOrder(order1); waiter.takeOrder(order2); waiter.undoLastOrder(); waiter.submitOrders(); } }客户点餐成功 客户点餐成功 服务员撤销最后一个订单... 厨师取消制作鱼香肉丝清理食材 服务员开始提交所有订单给厨师... 厨师宫保鸡丁制作完成 Process finished with exit code 0六、优缺点6.1 优点彻底解耦调用者和接收者 调用者如餐厅服务员只需要调用命令的execute()方法完全不用知道接收者厨师是谁、具体怎么执行做菜步骤接收者也无需关心谁发起了请求。极易扩展新命令 新增一个命令如新增 “麻婆豆腐” 菜品只需新增一个具体命令类无需修改原有代码完全符合 “开闭原则”。天然支持命令的撤销 / 重做、排队、日志记录 命令对象封装了执行的全部信息做什么、谁来做因此可以轻松实现可灵活组合命令宏命令可以将多个命令组合成一个 “宏命令”复合命令一次执行多个操作。6.2 缺点类数量膨胀增加系统复杂度 每一个具体的请求如每一道菜品、遥控器的每一个按键功能都需要对应一个具体命令类当系统中有大量命令时类的数量会急剧增加。简单场景下显得 “过度设计” 如果系统只有少量固定的命令且不需要撤销、排队、日志等功能使用命令模式会增加不必要的层级调用者→命令→接收者反而让代码更复杂。命令结果难以直接返回 命令模式的execute()方法通常是void类型无返回值如果需要获取接收者的执行结果如厨师做菜耗时、订单金额需要额外设计如给命令对象加结果属性增加了代码复杂度。七、适用场景7.1 适用需要解耦调用者和接收者的场景需要支持撤销 / 重做的场景需要对请求进行排队 / 日志记录 / 事务处理的场景需要批量执行多个操作的场景7.2 不适合系统只有少量固定的命令且不需要撤销、排队等扩展功能对性能要求极高的场景命令模式多一层封装会有轻微的性能开销简单的业务逻辑直接调用方法比封装命令更简洁的场景。八、对比学习8.1 策略模式对比Java 设计模式・策略模式篇从思想到代码实现-CSDN博客两者都属于行为型模式且都有 “封装不同逻辑” 的特征但核心目标完全不同。维度命令模式策略模式核心目标封装请求 / 操作“做什么”封装算法 / 策略“怎么做”角色关系调用者→命令→接收者三层解耦环境类→策略两层解耦核心能力支持撤销、排队、日志管理请求算法可替换优化执行逻辑典型场景点餐、遥控器、撤销操作支付方式、排序算法、折扣计算8.2 装饰器模式对比Java 设计模式・装饰器模式篇从思想到代码实现-CSDN博客两者都属于 “封装”但装饰器是 “增强功能”命令模式是 “封装操作”属于不同类型装饰器是结构型命令是行为型。维度命令模式装饰器模式模式类型行为型关注操作的执行 / 管理结构型关注对象功能的增强核心目标封装请求解耦调用者和接收者动态给对象添加功能不改变原有逻辑实现方式命令实现统一接口绑定接收者装饰器包裹原对象实现相同接口典型场景点餐、遥控器给咖啡加奶、加糖给日志加时间戳8.3 模板方法模式对比Java 设计模式・模板方法模式篇从思想到代码实现-CSDN博客两者都涉及 “操作的执行”但核心是 “灵活替换操作” vs “固定流程 局部定制”。维度命令模式模板方法模式核心逻辑封装独立的、可替换的单个操作固定整体流程只定制局部步骤如 “做套餐”固定流程 备料→烹饪→装盘仅 “烹饪” 步骤可定制灵活性操作可完全替换点鱼香肉丝 / 宫保鸡丁流程固定仅局部步骤可改套餐流程不变只换菜品做法角色关系调用者→命令→接收者三层解耦父类定流程子类重写步骤继承关系典型场景点餐、遥控器框架流程如 Spring 初始化、标准化流程如考试审题→答题→交卷九、源码举例 Runnable9.1 角色对应命令模式角色JDK 中的实现抽象命令CommandRunnable接口run()方法/Callable接口call()方法具体命令ConcreteCommand自定义的Runnable实现类如new Runnable() { ... }调用者InvokerThreadPoolExecutor线程池、Thread类接收者Receiver自定义run()方法里的业务逻辑如打印、计算、IO 操作9.2 抽象命令FunctionalInterface public interface Runnable { public abstract void run(); }9.2 调用者public class Thread implements Runnable { ... private Runnable target; ... public synchronized void start() { if (threadStatus ! 0) throw new IllegalThreadStateException(); group.add(this); boolean started false; try { start0(); started true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { } } } private native void start0(); Override public void run() { if (target ! null) { target.run(); } } ... }十、其它设计模式Java 设计模式・总结目录篇从思想到代码实现-CSDN博客