Java 设计模式之策略模式:灵活切换算法的艺术

本文涉及的产品
多模态交互后付费免费试用,全链路、全Agent
简介: 策略模式通过封装不同算法并实现灵活切换,将算法与使用解耦。以支付为例,微信、支付宝等支付方式作为独立策略,购物车根据选择调用对应支付逻辑,提升代码可维护性与扩展性,避免冗长条件判断,符合开闭原则。

Java 设计模式之策略模式:灵活切换算法的艺术

在软件开发中,我们经常需要为一个问题提供多种解决方案,并且希望能够根据不同场景灵活切换。比如排序算法有冒泡排序、快速排序、归并排序等;支付方式有微信支付、支付宝支付、银行卡支付等。如果将这些算法硬编码到业务逻辑中,会导致代码臃肿、难以维护。策略模式(Strategy Pattern)正是解决这类问题的最佳实践。

什么是策略模式?

策略模式是一种行为型设计模式,它定义了一系列算法,将每个算法封装起来,并使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户,从而实现算法的灵活切换。

这种模式的核心思想是分离算法的定义与使用,通过面向接口编程,使得客户端可以在运行时根据需要选择不同的算法。

策略模式的核心角色

策略模式通常包含三个核心角色:

  1. 抽象策略(Strategy):定义所有支持的算法的公共接口,通常是一个接口或抽象类
  2. 具体策略(Concrete Strategy):实现抽象策略定义的接口,提供具体的算法实现
  3. 环境类(Context):持有一个策略对象的引用,负责使用策略对象,客户端通过环境类来使用策略

策略模式的工作原理

  1. 定义抽象策略接口,声明所有具体策略都需要实现的方法
  2. 实现多个具体策略类,每个类对应一种具体的算法
  3. 环境类中维护一个抽象策略的引用,提供方法用于设置具体策略
  4. 客户端创建具体策略对象,通过环境类的方法设置策略
  5. 环境类在需要时调用策略对象的方法,执行具体算法

策略模式的代码实现

我们以 "购物车支付系统" 为例来实现策略模式。一个购物车需要支持多种支付方式,并且可以根据用户选择动态切换。

1. 抽象策略接口

首先定义支付策略的抽象接口,所有支付方式都需要实现这个接口:

// 支付策略接口
public interface PaymentStrategy {
   
    // 支付方法
    void pay(double amount);

    // 获取支付方式名称
    String getPaymentName();
}

2. 具体策略实现

实现不同的支付方式作为具体策略:

// 微信支付
public class WechatPayment implements PaymentStrategy {
   
    private String wechatAccount;

    public WechatPayment(String wechatAccount) {
   
        this.wechatAccount = wechatAccount;
    }

    @Override
    public void pay(double amount) {
   
        System.out.println("使用微信支付 " + amount + " 元,账号:" + wechatAccount);
        // 实际支付逻辑:调用微信支付API等
    }

    @Override
    public String getPaymentName() {
   
        return "微信支付";
    }
}

// 支付宝支付
public class AlipayPayment implements PaymentStrategy {
   
    private String alipayAccount;

    public AlipayPayment(String alipayAccount) {
   
        this.alipayAccount = alipayAccount;
    }

    @Override
    public void pay(double amount) {
   
        System.out.println("使用支付宝支付 " + amount + " 元,账号:" + alipayAccount);
        // 实际支付逻辑:调用支付宝支付API等
    }

    @Override
    public String getPaymentName() {
   
        return "支付宝支付";
    }
}

// 银行卡支付
public class BankCardPayment implements PaymentStrategy {
   
    private String cardNumber;
    private String cardHolder;

    public BankCardPayment(String cardNumber, String cardHolder) {
   
        this.cardNumber = cardNumber;
        this.cardHolder = cardHolder;
    }

    @Override
    public void pay(double amount) {
   
        System.out.println("使用银行卡支付 " + amount + " 元,卡号:" + maskCardNumber(cardNumber) + ",持卡人:" + cardHolder);
        // 实际支付逻辑:调用银行支付API等
    }

    // 隐藏卡号中间部分,保护隐私
    private String maskCardNumber(String cardNumber) {
   
        if (cardNumber.length() <= 8) {
   
            return cardNumber;
        }
        return cardNumber.substring(0, 4) + "****" + cardNumber.substring(cardNumber.length() - 4);
    }

    @Override
    public String getPaymentName() {
   
        return "银行卡支付";
    }
}

3. 环境类实现

实现购物车作为环境类,使用支付策略进行支付:

import java.util.ArrayList;
import java.util.List;

// 购物车(环境类)
public class ShoppingCart {
   
    private List<String> items;
    private PaymentStrategy paymentStrategy;

    public ShoppingCart() {
   
        items = new ArrayList<>();
    }

    // 添加商品
    public void addItem(String item) {
   
        items.add(item);
    }

    // 移除商品
    public void removeItem(String item) {
   
        items.remove(item);
    }

    // 计算总价(简化处理,实际应根据商品价格计算)
    public double calculateTotal() {
   
        // 这里简化为每个商品10元
        return items.size() * 10.0;
    }

    // 设置支付策略
    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
   
        this.paymentStrategy = paymentStrategy;
    }

    // 执行支付
    public void checkout() {
   
        if (paymentStrategy == null) {
   
            System.out.println("请选择支付方式");
            return;
        }

        double total = calculateTotal();
        System.out.println("购物车商品:" + items);
        System.out.println("总价:" + total + "元");
        paymentStrategy.pay(total);
        System.out.println("支付完成!");
    }
}

4. 客户端测试

public class ShoppingCartDemo {
   
    public static void main(String[] args) {
   
        // 创建购物车
        ShoppingCart cart = new ShoppingCart();

        // 添加商品
        cart.addItem("Java编程思想");
        cart.addItem("设计模式详解");
        cart.addItem("算法导论");

        // 选择微信支付
        System.out.println("=== 使用微信支付 ===");
        cart.setPaymentStrategy(new WechatPayment("wx123456789"));
        cart.checkout();

        // 选择支付宝支付
        System.out.println("\n=== 使用支付宝支付 ===");
        cart.setPaymentStrategy(new AlipayPayment("alipay987654321"));
        cart.checkout();

        // 选择银行卡支付
        System.out.println("\n=== 使用银行卡支付 ===");
        cart.setPaymentStrategy(new BankCardPayment("6222021234567890123", "张三"));
        cart.checkout();
    }
}

运行结果:

=== 使用微信支付 ===
购物车商品:[Java编程思想, 设计模式详解, 算法导论]
总价:30.0元
使用微信支付 30.0 元,账号:wx123456789
支付完成!

=== 使用支付宝支付 ===
购物车商品:[Java编程思想, 设计模式详解, 算法导论]
总价:30.0元
使用支付宝支付 30.0 元,账号:alipay987654321
支付完成!

=== 使用银行卡支付 ===
购物车商品:[Java编程思想, 设计模式详解, 算法导论]
总价:30.0元
使用银行卡支付 30.0 元,卡号:6222****0123,持卡人:张三
支付完成!

策略模式与工厂模式的结合

在实际开发中,策略模式常与工厂模式结合使用,由工厂负责创建具体策略对象,进一步降低客户端与具体策略的耦合。

我们添加一个支付策略工厂:

// 支付策略工厂
public class PaymentStrategyFactory {
   
    // 根据支付方式名称创建对应的支付策略
    public static PaymentStrategy createPaymentStrategy(String type, String... args) {
   
        switch (type.toLowerCase()) {
   
            case "wechat":
                if (args.length < 1) {
   
                    throw new IllegalArgumentException("微信支付需要账号参数");
                }
                return new WechatPayment(args[0]);
            case "alipay":
                if (args.length < 1) {
   
                    throw new IllegalArgumentException("支付宝支付需要账号参数");
                }
                return new AlipayPayment(args[0]);
            case "bankcard":
                if (args.length < 2) {
   
                    throw new IllegalArgumentException("银行卡支付需要卡号和持卡人参数");
                }
                return new BankCardPayment(args[0], args[1]);
            default:
                throw new IllegalArgumentException("不支持的支付方式:" + type);
        }
    }
}

客户端使用工厂创建策略:

// 使用工厂模式创建支付策略
public class StrategyWithFactoryDemo {
   
    public static void main(String[] args) {
   
        ShoppingCart cart = new ShoppingCart();
        cart.addItem("数据结构");
        cart.addItem("计算机网络");

        // 通过工厂创建支付策略
        PaymentStrategy wechatPay = PaymentStrategyFactory.createPaymentStrategy("wechat", "wx987654321");
        cart.setPaymentStrategy(wechatPay);
        cart.checkout();
    }
}

策略模式的优缺点

优点

  1. 灵活性高:可以在运行时动态切换算法,无需修改原有代码
  2. 代码复用性好:将算法封装在独立的策略类中,便于复用
  3. 符合开闭原则:新增算法只需添加新的策略类,无需修改环境类和其他策略
  4. 避免大量条件判断:用多态替代复杂的 if-else 或 switch-case 语句
  5. 职责单一:每个策略类只负责实现一种算法,符合单一职责原则

缺点

  1. 类数量增加:每个算法都需要一个对应的策略类,可能导致类数量增多
  2. 客户端需要了解策略:客户端必须知道所有策略的存在,才能选择合适的策略
  3. 策略间通信问题:策略类之间无法直接通信,如需共享数据需通过环境类

策略模式的适用场景

  1. 当一个问题有多种解决方案,且需要在不同场景下切换时
  2. 当代码中存在大量与算法相关的条件判断语句时
  3. 当需要隐藏算法的实现细节,只暴露其接口时
  4. 当希望客户端可以扩展或替换现有算法时

常见应用场景:

  • 排序算法的选择
  • 不同的校验规则
  • 多种支付方式
  • 不同的日志记录方式
  • 各种压缩算法

总结

策略模式通过分离算法的定义与使用,实现了算法的灵活切换和扩展,有效解决了条件判断语句臃肿的问题。它将每个算法封装成独立的策略类,使得算法可以独立于客户端变化。

在实际开发中,策略模式特别适合处理那些具有多种变体的业务逻辑。合理运用策略模式,可以使代码更加清晰、灵活,也更易于维护和扩展。

需要注意的是,策略模式增加了类的数量,并且要求客户端了解不同策略的区别,因此在策略数量不多且变化不频繁的场景下,过度使用策略模式可能会适得其反。

目录
相关文章
|
15小时前
|
编解码 数据可视化 数据挖掘
空间转录组: Visium HD 数据集分析 (1)
空间转录组: Visium HD 数据集分析 (1)
47 26
空间转录组: Visium HD 数据集分析 (1)
|
5天前
|
人工智能 安全 架构师
不只是聊天:从提示词工程看AI助手的优化策略
不只是聊天:从提示词工程看AI助手的优化策略
182 119
|
3天前
|
人工智能 vr&ar UED
获奖公布|第十九届"挑战杯"竞赛2025年度中国青年科技创新"揭榜挂帅"擂台赛阿里云“AI技术助力乡村振兴”专题赛拟授奖名单公示
获奖公布|第十九届"挑战杯"竞赛2025年度中国青年科技创新"揭榜挂帅"擂台赛阿里云“AI技术助力乡村振兴”专题赛拟授奖名单公示
|
4天前
|
算法 API 流计算
《3D古城场景角色碰撞优化的实战指南》
本文聚焦开放世界3A项目“燕云古城废墟”场景的角色物理碰撞优化,记录从解决“穿模”“帧率骤降”等核心问题切入的工程化实践。先针对静态物体碰撞体冗余,设计“层级碰撞体”方案并制定精度规范,大幅降低计算量;再通过“预破碎资源池”优化可破坏物体,减少实时破碎的性能消耗;开发“动态碰撞剔除系统”,基于距离与视野实现碰撞计算按需触发;结合移动端特性,通过碰撞简化与物理步长调整完成多设备适配;最后构建“碰撞-动画协同系统”,提升交互真实感。
74 32
|
4天前
|
人工智能 自然语言处理 安全
用AI重构人机关系,OPPO智慧服务带来了更“懂你”的体验
OPPO在2025开发者大会上展现智慧服务新范式:通过大模型与意图识别技术,构建全场景入口矩阵,实现“服务找人”。打通负一屏、小布助手等系统级入口,让服务主动触达用户;为开发者提供统一意图标准、一站式平台与安全准则,降低适配成本,共建开放生态。
81 31
|
13天前
|
云栖大会
阿里云产品九月刊来啦
2025云栖大会重磅合集,阿里云各产品重大升级发布
101 23
|
29天前
|
Java 数据库连接 应用服务中间件
基于springboot的母婴健康交流系统
本平台旨在为新手父母提供专业、系统的婴幼儿健康知识与交流空间,整合权威资源,解决育儿信息碎片化与误导问题,支持经验分享与情感互助,助力科学育儿。
|
29天前
|
存储 算法 调度
【复现】【遗传算法】考虑储能和可再生能源消纳责任制的售电公司购售电策略(Python代码实现)
【复现】【遗传算法】考虑储能和可再生能源消纳责任制的售电公司购售电策略(Python代码实现)
139 26
|
2天前
|
机器学习/深度学习 人工智能 自然语言处理
AI Compass前沿速览:ChatGPT Atlas、Claude Code、Haiku 4.5、Veo 3.1、nanochat、DeepSeek-OCR
AI Compass前沿速览:ChatGPT Atlas、Claude Code、Haiku 4.5、Veo 3.1、nanochat、DeepSeek-OCR
AI Compass前沿速览:ChatGPT Atlas、Claude Code、Haiku 4.5、Veo 3.1、nanochat、DeepSeek-OCR
|
5天前
|
机器学习/深度学习 人工智能 监控
智能的三重境界:从感知、认知到决策的进化
智能的三重境界:从感知、认知到决策的进化
199 121