找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2422

积分

0

好友

343

主题
发表于 14 小时前 | 查看: 4| 回复: 0

在面向对象分析与设计(OOAD)中,设计模式是解决特定问题的经典范式,而行为型模式则专注于优化对象之间的交互与职责分配。你是否曾为系统中对象间的紧耦合、逻辑复用困难或状态管理混乱而头疼?本文将带你深入剖析行为型模式,通过电商订单、支付、退款等真实场景,结合详细的UML类图与Java代码,掌握如何运用策略、观察者、责任链和状态模式来构建高内聚、低耦合的优雅系统。

01 行为型模式的核心定位与设计思想

1.1 核心解决问题

在没有合理运用行为型模式的代码中,对象间的协作通常伴随着三大痛点:

  • 交互耦合严重:对象之间直接调用,形成复杂的网状依赖。一旦某个对象需要修改,往往会引发“牵一发而动全身”的连锁反应。
  • 行为逻辑僵化:可变的业务逻辑(如各种折扣算法)常常以 if-elseswitch 的形式硬编码在业务类中。新增一种逻辑就意味着要修改原有代码,这直接违反了开放-封闭原则。
  • 职责边界模糊:一个类往往同时承担数据存储和行为执行的双重职责,导致类变得臃肿,难以维护和复用。

行为型模式正是为了解决这些问题而生。其核心设计思想在于将行为或算法封装成独立的对象,从而将行为与发出请求的对象或执行行为的对象解耦。

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-elseswitch)。典型场景如订单状态流转、游戏角色状态、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链)都内置了这些模式的实现,理解它们能帮助我们更好地使用这些框架。

设计模式是通往高质量软件设计的阶梯,但最终目标是写出清晰、健壮、易于维护的代码。希望本文的解析能帮助你在面对对象行为设计的挑战时,找到优雅的解决方案。如果你想与其他开发者交流更多关于系统架构与设计的心得,欢迎前往 云栈社区 参与讨论。




上一篇:SPI通信协议四种工作模式详解:引脚配置、时序分析与嵌入式应用
下一篇:MySQL开发者与DBA必备:三款高效的Navicat替代工具评测
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-16 20:41 , Processed in 0.301012 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表