在面向对象分析与设计(OOAD)中,设计模式是解决特定问题的经典范式,而行为型模式则专注于优化对象之间的交互与职责分配。你是否曾为系统中对象间的紧耦合、逻辑复用困难或状态管理混乱而头疼?本文将带你深入剖析行为型模式,通过电商订单、支付、退款等真实场景,结合详细的UML类图与Java代码,掌握如何运用策略、观察者、责任链和状态模式来构建高内聚、低耦合的优雅系统。
01 行为型模式的核心定位与设计思想
1.1 核心解决问题
在没有合理运用行为型模式的代码中,对象间的协作通常伴随着三大痛点:
- 交互耦合严重:对象之间直接调用,形成复杂的网状依赖。一旦某个对象需要修改,往往会引发“牵一发而动全身”的连锁反应。
- 行为逻辑僵化:可变的业务逻辑(如各种折扣算法)常常以
if-else 或 switch 的形式硬编码在业务类中。新增一种逻辑就意味着要修改原有代码,这直接违反了开放-封闭原则。
- 职责边界模糊:一个类往往同时承担数据存储和行为执行的双重职责,导致类变得臃肿,难以维护和复用。
行为型模式正是为了解决这些问题而生。其核心设计思想在于将行为或算法封装成独立的对象,从而将行为与发出请求的对象或执行行为的对象解耦。
1.2 设计原则体现
行为型模式是诸多面向对象设计原则的集大成者,主要体现在:
- 依赖倒置原则:高层模块不依赖于低层模块的具体实现,二者都应依赖于抽象接口。
- 开放-封闭原则:系统应对扩展开放,对修改封闭。新增一种行为时,只需添加新类,无需改动现有代码。
- 单一职责原则:每个类应该只有一个引起它变化的原因。行为型模式帮助我们将“做什么”(数据)和“怎么做”(行为)的职责分离。
- 里氏替换原则:程序中所有引用基类(接口)的地方,必须能透明地使用其子类的对象。
02 核心行为型模式详解
2.1 策略模式
1. 核心场景
当你需要定义一族可互换的算法,并希望能在运行时动态选择使用哪个算法时,策略模式是理想选择。典型场景如电商系统的折扣计算:优惠券折扣、会员折扣、满减折扣等。如果使用硬编码的 if-else 判断,代码会变得难以维护和扩展。
2. 设计思路
策略模式定义了一系列算法,并将每一个算法封装起来,使它们可以相互替换。它让算法的变化独立于使用算法的客户。这恰恰是构建灵活、可扩展后端系统的关键思想,你可以在 云栈社区的架构板块 找到更多关于此类设计决策的深度讨论。
- 策略接口:定义所有支持算法的公共接口。
- 具体策略类:实现策略接口,封装具体的算法。
- 上下文类:持有一个策略对象的引用,并提供一个接口供客户端设置或切换策略。
3. UML 类图

4. 代码实现
定义策略接口:
// 折扣策略接口:统一所有折扣算法的接口
public interface DiscountStrategy {
// 计算折扣后金额(参数:订单原价)
BigDecimal calculate(BigDecimal originalPrice);
}
定义具体策略类:
// 优惠券折扣策略
public class CouponStrategy implements DiscountStrategy {
private BigDecimal couponAmount;
public CouponStrategy(BigDecimal couponAmount) {
this.couponAmount = couponAmount;
}
@Override
public BigDecimal calculate(BigDecimal originalPrice) {
BigDecimal finalPrice = originalPrice.subtract(couponAmount);
return finalPrice.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : finalPrice;
}
}
// 会员折扣策略(9折)
public class MemberStrategy implements DiscountStrategy {
private static final BigDecimal MEMBER_DISCOUNT = new BigDecimal("0.9");
@Override
public BigDecimal calculate(BigDecimal originalPrice) {
return originalPrice.multiply(MEMBER_DISCOUNT).setScale(2, BigDecimal.ROUND_HALF_UP);
}
}
定义上下文类:
// 订单折扣上下文:管理策略切换与执行
public class OrderDiscountContext {
private DiscountStrategy strategy;
public void setStrategy(DiscountStrategy strategy) {
this.strategy = strategy;
}
public BigDecimal executeDiscount(BigDecimal originalPrice) {
if (strategy == null) {
throw new RuntimeException("请先设置折扣策略");
}
return strategy.calculate(originalPrice);
}
}
客户端调用:
public class StrategyTest {
public static void main(String[] args) {
BigDecimal originalPrice = new BigDecimal("299");
OrderDiscountContext context = new OrderDiscountContext();
context.setStrategy(new CouponStrategy(new BigDecimal("10")));
System.out.println("优惠券折扣后金额:" + context.executeDiscount(originalPrice));
context.setStrategy(new MemberStrategy());
System.out.println("会员折扣后金额:" + context.executeDiscount(originalPrice));
}
}
2.2 观察者模式
1. 核心场景
当一个对象(目标对象)的状态发生改变,所有依赖于它的对象(观察者对象)都需要得到通知并自动更新时,观察者模式可以完美解耦这种一对多的依赖关系。例如,订单支付成功后,需要通知库存、物流、用户消息等多个系统。
2. 设计思路
观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
- 抽象主题:提供注册、删除和通知观察者的接口。
- 具体主题:维护观察者列表,状态改变时通知所有观察者。
- 抽象观察者:定义接收通知的更新接口。
- 具体观察者:实现更新接口,以响应主题的状态变更。
3. UML 类图

4. 代码实现
定义订单实体和观察者接口:
// 订单实体
public class Order {
private String orderId;
private String orderStatus;
// 构造方法、getter/setter
}
// 抽象观察者接口
public interface Observer {
void update(Order order);
}
// 具体观察者:库存系统
public class InventoryObserver implements Observer {
@Override
public void update(Order order) {
System.out.println("库存系统:扣减订单" + order.getOrderId() + "的商品库存。");
}
}
定义主题接口及实现:
// 抽象主题接口
public interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyObservers(Order order);
}
// 具体主题:订单状态发布者
public class ConcreteOrderSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
@Override
public void attach(Observer observer) { observers.add(observer); }
@Override
public void detach(Observer observer) { observers.remove(observer); }
@Override
public void notifyObservers(Order order) {
for (Observer observer : observers) {
observer.update(order);
}
}
public void changeOrderStatus(Order order) {
System.out.println("订单状态变更为:" + order.getOrderStatus());
this.notifyObservers(order);
}
}
客户端调用:
public class ObserverTest {
public static void main(String[] args) {
ConcreteOrderSubject subject = new ConcreteOrderSubject();
subject.attach(new InventoryObserver());
subject.attach(new LogisticsObserver()); // 假设已定义
Order paidOrder = new Order("123", "已支付");
subject.changeOrderStatus(paidOrder);
}
}
2.3 责任链模式
1. 核心场景
当你想让多个对象都有机会处理同一个请求,并且希望避免请求发送者与接收者之间的耦合时,可以使用责任链模式。典型场景如多级审批(费用报销)、过滤器链(Web请求处理)或日志记录器。
2. 设计思路
将处理请求的对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
- 抽象处理者:定义处理请求的接口,并持有对下一个处理者的引用。
- 具体处理者:实现处理请求的具体逻辑,如果自己不能处理,则传递给链上的下一个处理者。
3. UML 类图

4. 代码实现
定义抽象处理者:
// 退款审核抽象处理者
public abstract class RefundHandler {
protected RefundHandler nextHandler;
public void setNextHandler(RefundHandler nextHandler) {
this.nextHandler = nextHandler;
}
public abstract void handleRefund(BigDecimal refundAmount, String orderId);
}
定义具体处理者:
// 普通客服处理者(≤100元)
public class CustomerHandler extends RefundHandler {
private static final BigDecimal MAX_AMOUNT = new BigDecimal("100");
@Override
public void handleRefund(BigDecimal refundAmount, String orderId) {
if (refundAmount.compareTo(MAX_AMOUNT) <= 0) {
System.out.println("客服审核通过订单" + orderId + "的" + refundAmount + "元退款。");
} else if (nextHandler != null) {
nextHandler.handleRefund(refundAmount, orderId);
}
}
}
构建责任链并调用:
public class ChainTest {
public static void main(String[] args) {
RefundHandler customer = new CustomerHandler();
RefundHandler supervisor = new SupervisorHandler(); // 主管
RefundHandler manager = new ManagerHandler(); // 经理
customer.setNextHandler(supervisor);
supervisor.setNextHandler(manager);
// 处理不同金额的退款
customer.handleRefund(new BigDecimal("50"), "order001");
customer.handleRefund(new BigDecimal("500"), "order002");
}
}
2.4 状态模式
1. 核心场景
当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,使用状态模式可以消除庞大的条件分支语句(if-else 或 switch)。典型场景如订单状态流转、游戏角色状态、TCP连接状态等。
2. 设计思路
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
- 抽象状态:定义一个接口,用以封装与上下文的一个特定状态相关的行为。
- 具体状态:每一个子类实现一个与上下文某个状态相关的行为。
- 上下文:维护一个具体状态子类的实例,这个实例定义当前的状态。
3. UML 类图

4. 代码实现
定义抽象状态:
// 订单抽象状态
public interface OrderState {
void payOrder(OrderContext context);
void shipOrder(OrderContext context);
void signOrder(OrderContext context);
// ... 其他行为
}
定义具体状态:
// 待支付状态
public class WaitPayState implements OrderState {
@Override
public void payOrder(OrderContext context) {
System.out.println("执行支付...");
context.setCurrentState(new PaidState()); // 状态流转
}
@Override
public void shipOrder(OrderContext context) {
throw new UnsupportedOperationException("待支付状态不能发货");
}
// ... 其他方法实现
}
定义上下文:
// 订单上下文
public class OrderContext {
private OrderState currentState;
private String orderId;
public OrderContext(String orderId) {
this.orderId = orderId;
this.currentState = new WaitPayState(); // 初始状态
}
public void setCurrentState(OrderState state) {
this.currentState = state;
}
// 委托给当前状态对象执行
public void payOrder() {
currentState.payOrder(this);
}
public void shipOrder() {
currentState.shipOrder(this);
}
}
客户端调用:
public class StateTest {
public static void main(String[] args) {
OrderContext order = new OrderContext("order_888");
order.payOrder(); // 从“待支付”流转到“已支付”
order.shipOrder(); // 从“已支付”流转到“已发货”
// order.payOrder(); // 此时再调用会抛出异常
}
}
03 行为型模式对比与选型指南
| 模式 |
核心意图 |
典型场景 |
关键区别 |
| 策略模式 |
封装可互换的算法族,使它们可以独立于使用它们的客户端而变化。 |
折扣计算、支付方式、排序算法 |
关注算法的选择和替换。 |
| 观察者模式 |
定义对象间的一种一对多的依赖关系,当一个对象状态改变时,所有依赖它的对象都会得到通知。 |
事件监听、消息推送、MVC模型更新 |
关注状态变化的广播通知。 |
| 责任链模式 |
将请求的发送者和接收者解耦,使多个对象都有机会处理这个请求。 |
审批流程、过滤器链、异常处理 |
关注请求的链式传递与处理。 |
| 状态模式 |
允许一个对象在其内部状态改变时改变它的行为。 |
订单状态机、工作流、游戏角色状态 |
关注状态驱动的行为变化,消除条件分支。 |
04 总结
行为型设计模式为我们提供了管理复杂对象交互的蓝图。策略模式让算法灵活可配;观察者模式解耦了事件发布与订阅;责任链模式使得请求处理流程清晰可扩展;状态模式则将繁琐的状态判断转化为清晰的对象协作。
掌握这些模式的关键不在于死记硬背其结构,而在于理解其背后“封装变化”、“松耦合”的核心思想。在实际的 Java 项目开发中,应结合具体业务场景灵活运用,避免过度设计。许多主流框架(如Spring的事件机制、Servlet的Filter链)都内置了这些模式的实现,理解它们能帮助我们更好地使用这些框架。
设计模式是通往高质量软件设计的阶梯,但最终目标是写出清晰、健壮、易于维护的代码。希望本文的解析能帮助你在面对对象行为设计的挑战时,找到优雅的解决方案。如果你想与其他开发者交流更多关于系统架构与设计的心得,欢迎前往 云栈社区 参与讨论。