Java设计模式-策略模式

Java设计模式-策略模式

模式概述

策略模式简介

核心思想:定义一系列算法(策略),将每个算法封装成独立的类,并使它们可以相互替换。策略模式让算法的变化独立于使用它的客户端,从而避免大量条件判断语句,提升代码的可维护性和扩展性。

模式类型:行为型设计模式(关注对象间的交互与职责分配)。

作用

  • 解耦策略定义与使用:策略的具体实现与调用逻辑分离,客户端只需关注策略接口;
  • 消除条件语句:通过策略替换替代复杂的if-else或switch-case判断;
  • 符合开闭原则:新增策略只需添加新策略类,无需修改现有代码;
  • 提高复用性:策略类可被多个客户端共享使用。

典型应用场景

  • 支付方式选择(支付宝、微信、信用卡);
  • 数据校验规则(手机号、邮箱、身份证号校验);
  • 排序/加密算法切换(冒泡排序、快速排序、MD5、SHA-256);
  • 促销活动折扣(满减、折扣券、会员专属价)。

我认为:策略模式是"算法的动态切换器",通过将每个算法封装成独立的"策略零件",让业务逻辑像"组装机器"一样灵活选择不同的"零件",彻底告别冗长的条件判断。

课程目标

  • 理解策略模式的核心思想和经典应用场景
  • 识别应用场景,使用策略模式解决功能要求
  • 了解策略模式的优缺点

核心组件

角色-职责表

角色 职责 示例类名
抽象策略(Strategy) 定义所有具体策略的公共接口,声明策略需要实现的方法 PaymentStrategy
具体策略(Concrete Strategy) 实现抽象策略接口,封装具体的算法逻辑 AlipayStrategyWechatPayStrategy
上下文(Context) 持有策略接口引用,将客户端的请求委托给具体策略执行;提供策略切换方法 OrderService

类图

下面是一个简化的类图表示,展示了策略模式中的主要角色及其交互方式:
持有 实现 实现 实现 Context -PaymentStrategy strategy +setStrategy(PaymentStrategy strategy) +pay() <<interface>> PaymentStrategy +pay() AlipayStrategy +pay() WechatPayStrategy +pay() CreditCardStrategy +pay()


传统实现 VS 策略模式

案例需求

案例背景:电商系统中,订单支付支持支付宝、微信、信用卡三种方式。不同支付方式的支付逻辑不同(如签名验证、渠道调用),需要根据用户选择的支付方式执行对应逻辑。

传统实现(痛点版)

代码实现

java 复制代码
// 传统写法:上下文类直接包含策略判断逻辑
public class OrderService {
    // 支付方式类型(假设用字符串标识)
    private String paymentType;

    public void setPaymentType(String paymentType) {
        this.paymentType = paymentType;
    }

    public void pay() {
        if ("ALIPAY".equals(paymentType)) {
            // 支付宝支付逻辑:调用支付宝接口、生成签名、验证回调
            System.out.println("调用支付宝支付接口,完成支付");
        } else if ("WECHAT_PAY".equals(paymentType)) {
            // 微信支付逻辑:调用微信支付API、生成二维码、处理异步通知
            System.out.println("调用微信支付接口,生成支付二维码");
        } else if ("CREDIT_CARD".equals(paymentType)) {
            // 信用卡支付逻辑:验证卡号、有效期、CVV、调用银行接口
            System.out.println("调用银行接口,验证信用卡信息并支付");
        } else {
            System.out.println("未支持的支付方式");
        }
    }
}

// 使用示例
public class Client {
    public static void main(String[] args) {
        OrderService orderService = new OrderService();
        
        orderService.setPaymentType("ALIPAY");
        orderService.pay(); // 输出:调用支付宝支付接口,完成支付
        
        orderService.setPaymentType("WECHAT_PAY");
        orderService.pay(); // 输出:调用微信支付接口,生成支付二维码
        
        orderService.setPaymentType("CREDIT_CARD");
        orderService.pay(); // 输出:调用银行接口,验证信用卡信息并支付
    }
}

痛点总结

  • ​条件判断冗余​ :每新增一种支付方式,需在pay()方法中添加新的else if分支,代码膨胀严重;
  • 可维护性差 :支付逻辑与订单服务强耦合,修改某支付方式需改动OrderService类;
  • 扩展性低:违反开闭原则,新增支付方式(如"云闪付")需修改现有代码;
  • 复用性低:支付逻辑无法被其他业务(如退款、转账)复用。

策略模式 实现(优雅版)

代码实现

java 复制代码
// 1. 抽象策略接口:定义支付行为
interface PaymentStrategy {
    void pay(); // 支付操作
}

// 2. 具体策略类:支付宝支付(独立封装)
class AlipayStrategy implements PaymentStrategy {
    @Override
    public void pay() {
        System.out.println("调用支付宝支付接口,完成支付");
        // 实际逻辑:生成签名、调用支付宝API、处理回调等(独立维护)
    }
}

// 3. 具体策略类:微信支付(独立封装)
class WechatPayStrategy implements PaymentStrategy {
    @Override
    public void pay() {
        System.out.println("调用微信支付接口,生成支付二维码");
        // 实际逻辑:调用微信支付API、生成二维码、轮询回调等(独立维护)
    }
}

// 4. 具体策略类:信用卡支付(独立封装)
class CreditCardStrategy implements PaymentStrategy {
    @Override
    public void pay() {
        System.out.println("调用银行接口,验证信用卡信息并支付");
        // 实际逻辑:验证卡号/CVV/有效期、调用银行支付接口等(独立维护)
    }
}

// 5. 上下文类:订单服务(仅负责委托策略执行)
public class OrderService {
    private PaymentStrategy paymentStrategy; // 持有策略接口引用

    // 动态设置策略(支持运行时切换)
    public void setPaymentStrategy(PaymentStrategy strategy) {
        this.paymentStrategy = strategy;
    }

    // 执行支付(完全解耦具体策略)
    public void pay() {
        if (paymentStrategy == null) {
            throw new IllegalStateException("请先选择支付方式");
        }
        paymentStrategy.pay(); // 委托给具体策略执行
    }
}

// 使用示例
public class Client {
    public static void main(String[] args) {
        OrderService orderService = new OrderService();
        
        // 选择支付宝支付
        orderService.setPaymentStrategy(new AlipayStrategy());
        orderService.pay(); // 输出:调用支付宝支付接口,完成支付
        
        // 切换为微信支付
        orderService.setPaymentStrategy(new WechatPayStrategy());
        orderService.pay(); // 输出:调用微信支付接口,生成支付二维码
        
        // 切换为信用卡支付
        orderService.setPaymentStrategy(new CreditCardStrategy());
        orderService.pay(); // 输出:调用银行接口,验证信用卡信息并支付
    }
}

优势

  • 消除条件判断 :通过策略接口委托调用,避免了冗长的if-else分支;
  • 高扩展性 :新增支付方式(如UnionPayStrategy)只需实现PaymentStrategy接口,无需修改现有代码;
  • 低耦合:支付逻辑封装在独立策略类中,与订单服务解耦,便于单独测试和维护;
  • 行为复用:策略类可被其他业务(如退款服务)复用,减少重复代码。

局限

  • 类数量增加:若策略数量过多(如超过10种),会导致类膨胀,需合理设计(如结合工厂模式);
  • 策略初始化成本:若策略需要依赖大量参数(如支付配置),可能需要额外处理(如通过构造函数注入);
  • 客户端需了解策略差异:客户端需知道所有策略的存在,才能选择合适的策略(可通过上下文提供默认策略缓解)。

模式变体

  • 枚举策略:利用Java枚举特性,将每个策略定义为枚举值并实现策略接口(适合轻量级、固定的策略集合);

    java 复制代码
    enum PaymentTypeEnum implements PaymentStrategy {
        ALIPAY {
            @Override
            public void pay() { /* 支付宝逻辑 */ }
        },
        WECHAT_PAY {
            @Override
            public void pay() { /* 微信逻辑 */ }
        };
    }
  • 静态策略(单例策略):无状态的策略类通过单例模式创建,减少对象实例化开销(适合无状态的策略);

  • 策略工厂:通过工厂类动态创建策略对象(解耦策略的创建与使用,适合策略需要根据参数动态选择的场景);

    java 复制代码
    class StrategyFactory {
        public static PaymentStrategy getStrategy(String type) {
            switch (type) {
                case "ALIPAY": return new AlipayStrategy();
                case "WECHAT_PAY": return new WechatPayStrategy();
                default: throw new IllegalArgumentException("无效支付方式");
            }
        }
    }
  • 组合策略:通过组合多个简单策略实现复杂逻辑(适合策略间有依赖或需要动态叠加的场景)。


最佳实践

建议 理由
策略接口保持稳定 策略接口是客户端与策略交互的契约,频繁修改会影响所有策略实现类
具体策略尽量无状态 无状态的策略类可通过单例复用(如AlipayStrategy.INSTANCE),减少内存开销
上下文避免暴露策略细节 上下文仅暴露执行策略的方法(如pay()),隐藏策略的创建和切换逻辑(通过工厂或构建器优化)
为策略添加文档说明 明确每个策略的适用场景和约束(如"信用卡支付需验证CVV"),帮助客户端正确选择
结合工厂模式创建策略 当策略创建逻辑复杂(如依赖配置、数据库查询)时,通过工厂类封装创建过程

一句话总结

策略模式通过将算法族封装为独立的策略类并动态切换,彻底解决了传统实现中条件判断冗余、扩展性差的问题,是实现灵活业务逻辑的经典解决方案。

如果关注Java设计模式内容,可以查阅作者的其他Java设计模式系列文章。😊