责任链模式(Chain of Responsibility Pattern)
概念
责任链模式是一种行为型设计模式,它将请求的发送者和接收者解耦,让多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递请求,直到有对象处理它为止。
通俗理解:就像公司的审批流程,员工提交报销申请后,会依次经过组长 → 经理 → 总监 → 财务,每一级都有自己的审批权限,超出权限就传递给下一级。
核心角色
- Handler(抽象处理者):定义处理请求的接口,包含下一个处理者的引用
- ConcreteHandler(具体处理者):实现处理请求的具体逻辑,如果自己不能处理则传递给下一个处理者
- Client(客户端):创建责任链并发起请求
核心思想
让复杂的业务流程变得像搭积木一样灵活,可以根据不同场景组装不同的链条。核心优势在于:
- 解耦:请求发送者不需要知道谁会处理请求
- 灵活:可以动态增加、删除、调整处理节点
- 单一职责:每个处理者只关注自己的处理逻辑
实际应用场景
场景1:订单校验流程
在电商系统中,订单提交后需要经过多重校验:
订单请求 → 库存校验 → 优惠券校验 → 风控校验 → 支付校验 → 提交成功
传统方式的问题:
public void submitOrder(Order order) {
// 所有校验逻辑耦合在一起
if (!checkStock(order)) return;
if (!checkCoupon(order)) return;
if (!checkRisk(order)) return;
if (!checkPayment(order)) return;
// 如果要新增"黑名单校验",必须修改这里的代码
}
使用责任链模式:
// 只需新增一个黑名单校验处理器
BlacklistHandler blacklistHandler = new BlacklistHandler();
// 将其插入责任链中
stockHandler.setNext(couponHandler)
.setNext(blacklistHandler) // 新增节点
.setNext(riskHandler)
.setNext(paymentHandler);
场景2:动态配置责任链
不同促销活动需要不同的校验流程:
- 618活动:库存校验 → 优惠券校验 → 风控校验 → 支付校验
- 双十一活动:库存校验 → 优惠券校验 → 风控校验 → 黑名单校验 → 支付校验
通过配置文件或数据库动态组装责任链,无需修改代码即可适应不同业务场景。
优缺点
优点:
- 降低耦合度,请求发送者和接收者解耦
- 增强了给对象指派职责的灵活性
- 符合开闭原则,新增处理者无需修改原有代码
缺点:
- 请求可能得不到处理(链条末端没有处理)
- 性能问题,请求可能需要遍历整条链
- 调试不方便,需要跟踪整条链路
命令模式(Command Pattern)
概念
命令模式是一种行为型设计模式,它将请求封装成一个对象,从而让你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
通俗理解:把"做某件事"这个动作本身变成一个对象,这样就可以像操作普通对象一样操作这个动作。
核心角色
- Command(命令接口):定义执行操作的接口
- ConcreteCommand(具体命令):实现命令接口,持有接收者对象
- Receiver(接收者):真正执行业务逻辑的对象
- Invoker(调用者):持有命令对象,负责调用命令
- Client(客户端):创建具体命令对象并设置接收者
核心思想
把"动词"变成"名词"的过程,这是命令模式最精髓的理解:
- 动词(方法):只能被调用,调用完就消失了,无法控制
- 名词(对象):可以被传递、存储、修改、组合、撤销
通过将行为对象化,我们获得了对行为的控制能力,实现了创建和执行的解耦。
生动的案例:餐厅点餐系统
场景对比:
方式1:直接沟通(没有命令模式)
顾客A对厨师说:"来一碗面"
顾客B对厨师说:"来一碗饭"
问题:
- 只能按时间顺序执行
- 无法撤销订单
- 无法调整优先级
- 无法记录历史
- 厨师必须记住所有订单
方式2:订单纸条(使用命令模式)
顾客A写纸条:"一碗面" → 交给服务员
顾客B写纸条:"一碗饭" → 交给服务员
服务员将纸条按顺序交给厨师
优势:
- ✅ 可以撤销:顾客反悔,撕掉纸条即可
- ✅ 可以加急:VIP订单插队
- ✅ 可以修改:改菜品只需换纸条
- ✅ 可以对账:纸条就是凭证
- ✅ 可以排队:服务员统一管理订单
这就是将创建和执行解耦的威力!
代码示例
// 命令接口
interface Command {
void execute();
void undo();
}
// 具体命令
class OrderCommand implements Command {
private Chef chef; // 接收者
private String dish;
public void execute() {
chef.cook(dish);
}
public void undo() {
chef.cancel(dish);
}
}
// 调用者(服务员)
class Waiter {
private List<Command> orders = new ArrayList<>();
public void takeOrder(Command command) {
orders.add(command);
}
public void submitOrders() {
for (Command order : orders) {
order.execute();
}
}
}
实际应用场景
- 文本编辑器的撤销/重做功能
- 事务管理系统
- 任务队列和调度系统
- 宏命令(批量操作)
- 日志记录和审计
优缺点
优点:
- 解耦调用者和接收者
- 容易扩展新命令
- 可以实现撤销/重做
- 可以组合命令(宏命令)
缺点:
- 可能产生大量具体命令类
- 增加了系统复杂度
迭代器模式(Iterator Pattern)
概念
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。简单来说,就是提供一种统一的方式来遍历不同的集合结构。
通俗理解:就像遥控器,不管是电视、空调还是音响,都用同样的方式操作(上一个、下一个),不需要知道内部是怎么工作的。
核心思想
把复杂的遍历逻辑藏起来,给使用者一个简单统一的接口。让集合的遍历方式与集合的内部结构解耦。
核心角色
- Iterator(迭代器接口):定义访问和遍历元素的接口(hasNext、next等)
- ConcreteIterator(具体迭代器):实现迭代器接口,跟踪遍历的当前位置
- Aggregate(聚合接口):定义创建迭代器对象的接口
- ConcreteAggregate(具体聚合):实现创建相应迭代器的接口,返回具体迭代器实例
为什么需要迭代器模式
问题场景:
// 遍历数组
for (int i = 0; i < array.length; i++) {
process(array[i]);
}
// 遍历链表
Node current = head;
while (current != null) {
process(current.data);
current = current.next;
}
// 遍历树(需要递归或栈)
// 更复杂...
每种数据结构的遍历方式都不同,使用者需要了解内部结构,代码难以复用。
使用迭代器模式:
// 统一的遍历方式
Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
process(iterator.next());
}
实际应用
Java中最常见的就是Iterator接口:
List<String> list = new ArrayList<>();
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println(item);
}
// 或者使用增强for循环(底层也是迭代器)
for (String item : list) {
System.out.println(item);
}
优缺点
优点:
- 支持以不同方式遍历一个聚合对象
- 简化了聚合类的接口
- 可以同时进行多个遍历
- 符合单一职责原则
缺点:
- 对于简单的集合,使用迭代器可能比较繁琐
- 增加了系统复杂度
648



被折叠的 条评论
为什么被折叠?



