🤝 行为型模式
观察者 · 策略 · 模板方法 · 责任链 · 状态模式
1. 观察者模式?发布订阅的区别?
观察者模式:主题状态变化时自动通知所有订阅者。解耦"通知者"与"被通知者"。
应用:Spring 事件机制(ApplicationEvent + @EventListener)、MQ 的发布订阅模型(广义)、Swing/AWT 事件监听。
观察者 vs 发布-订阅:观察者模式中主题与观察者直接关联(主题持有观察者列表);发布-订阅中间有消息代理(Topic),完全解耦。Spring 事件本质是观察者(ApplicationEventPublisher 直接持有监听器列表,没有独立的 broker 进程);只有 MQ 这种经过消息代理中转的才是发布-订阅。
// 事件
class OrderCreatedEvent extends ApplicationEvent {
OrderCreatedEvent(Object source) { super(source); }
}
// 发布(业务代码解耦)
@Service class OrderService {
@Autowired ApplicationEventPublisher publisher;
public void create() {
// 订单逻辑...
publisher.publishEvent(new OrderCreatedEvent(this)); // 通知,不关心谁听
}
}
// 监听(可多个,互不感知)
@Component class SmsListener {
@EventListener
public void onOrder(OrderCreatedEvent e) { // 发短信 }
}
🎯 面试要点
- Spring 事件默认同步执行(同一线程),@Async + @EnableAsync 可异步——面试延伸点
- 观察者模式的本质:一对多的依赖,变化自动传播
2. 策略模式?和 if-else 的关系?
策略模式:定义一族算法,各自封装,运行时可互换。客户端依赖策略接口,不依赖具体算法。
if-else 消除:多个 if-else 分支各对应一个策略类 + 注册表(Map<类型, 策略>,构造时注册)。
interface PayStrategy { void pay(BigDecimal amount); }
@Component class WechatPay implements PayStrategy {
public void pay(BigDecimal a) { ... } }
@Component class Alipay implements PayStrategy { ... }
@Component class PayService {
private final Map<String, PayStrategy> strategies;
public PayService(List<PayStrategy> list) { // Spring 自动注入全部实现
strategies = list.stream().collect(Collectors.toMap(
s -> s.getClass().getSimpleName().replace("Pay", ""), s -> s));
}
public void pay(String type, BigDecimal a) {
strategies.get(type).pay(a); // 取代 if (type.equals("wx"))...
}
}
🎯 面试要点
- 策略 + 工厂 + 注册表是面试"如何消除大量 if-else"的标准答案
- 对比模板方法:模板方法固定骨架、子类改细节;策略是整体算法可替换
3. 模板方法模式?
模板方法:父类定义算法骨架(不可变流程),把变化的步骤留给子类实现(钩子方法)。"好莱坞原则"的体现:父类调子类。
应用:AbstractQueuedSynchronizer(AQS)——acquire 流程固定,tryAcquire 留给子类(见并发模块);Spring 的 JdbcTemplate(execute 骨架)、AbstractApplicationContext.refresh()。
abstract class DataParser {
public final void parse(String file) { // 骨架固定(final 防改写)
open(file);
for (String line : readLines()) process(line); // 流程固定
close();
}
protected abstract void open(String file); // 变化点:子类实现
protected abstract void process(String line);
protected void close() {} // 钩子:默认空实现
}
🎯 面试要点
- 和策略模式的对比是常考点:骨架固定 vs 算法互换
- AQS 是模板方法的教科书案例——结合并发模块一起答
4. 责任链模式?应用场景?
责任链:多个处理器串联,请求沿链传递直到被处理。解耦"发起者"与"处理者",动态编排处理顺序。
应用:
- Servlet Filter 链(过滤链)
- Spring MVC 拦截器链
- MyBatis 的拦截器(插件)
- Netty 的 Pipeline(Handler 链)
- 审批流、敏感词过滤(可中断)
abstract class Handler {
private Handler next;
public Handler setNext(Handler next) { this.next = next; return next; }
public final void handle(Request req) {
if (canHandle(req)) doHandle(req); // 能处理就处理
else if (next != null) next.handle(req); // 否则交给下一个
}
protected abstract boolean canHandle(Request r);
protected abstract void doHandle(Request r);
}
🎯 面试要点
- 链与列表的区别:链上的处理"顺序语义"(前置校验→业务→后置)
- 职责链模式 vs 装饰器:链是横向传递(请求移动),装饰器是纵向包裹(调用嵌套)
5. 状态模式?
状态模式:对象的行为随内部状态变化而变化——把每个状态封装成类,状态切换 = 切换状态对象。消除大量 if (state == ...) 分支。
应用:订单状态机(待支付→已支付→已发货→已收货)、工作流引擎、游戏角色状态。
🎯 面试要点
- 状态 vs 策略:策略是"算法互换"(外部选择);状态是"内部状态驱动"(状态自动迁移)——结构相似,语义不同
- 状态机是高频场景题:电商订单状态流转,答"状态模式 + 状态机表(当前状态/事件/动作/下一状态)"