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. 当希望客户端可以扩展或替换现有算法时

常见应用场景:

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

总结

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

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

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

目录
相关文章
|
23天前
|
设计模式 Java Spring
Java 设计模式之责任链模式:优雅处理请求的艺术
责任链模式通过构建处理者链,使请求沿链传递直至被处理,实现发送者与接收者的解耦。适用于审批流程、日志处理等多级处理场景,提升系统灵活性与可扩展性。
168 2
|
23天前
|
设计模式 网络协议 数据可视化
Java 设计模式之状态模式:让对象的行为随状态优雅变化
状态模式通过封装对象的状态,使行为随状态变化而改变。以订单为例,将待支付、已支付等状态独立成类,消除冗长条件判断,提升代码可维护性与扩展性,适用于状态多、转换复杂的场景。
211 0
|
22天前
|
设计模式 消息中间件 传感器
Java 设计模式之观察者模式:构建松耦合的事件响应系统
观察者模式是Java中常用的行为型设计模式,用于构建松耦合的事件响应系统。当一个对象状态改变时,所有依赖它的观察者将自动收到通知并更新。该模式通过抽象耦合实现发布-订阅机制,广泛应用于GUI事件处理、消息通知、数据监控等场景,具有良好的可扩展性和维护性。
189 8
|
1月前
|
存储 算法 搜索推荐
《数据之美》:Java数据结构与算法精要
本系列深入探讨数据结构与算法的核心原理及Java实现,涵盖线性与非线性结构、常用算法分类、复杂度分析及集合框架应用,助你提升程序效率,掌握编程底层逻辑。
|
设计模式 算法 Java
Java工厂策略模式介绍
本文介绍Java中工厂模式与策略模式的结合应用,通过工厂创建策略对象,实现灵活、可扩展的支付、折扣等业务场景,提升系统解耦与维护性。
164 3
|
29天前
|
存储 人工智能 算法
从零掌握贪心算法Java版:LeetCode 10题实战解析(上)
在算法世界里,有一种思想如同生活中的"见好就收"——每次做出当前看来最优的选择,寄希望于通过局部最优达成全局最优。这种思想就是贪心算法,它以其简洁高效的特点,成为解决最优问题的利器。今天我们就来系统学习贪心算法的核心思想,并通过10道LeetCode经典题目实战演练,带你掌握这种"步步为营"的解题思维。
|
2月前
|
设计模式 人工智能 算法
基于多设计模式的状态扭转设计:策略模式与责任链模式的实战应用
接下来,我会结合实战案例,聊聊如何用「策略模式 + 责任链模式」构建灵活可扩展的状态引擎,让抽奖系统的状态管理从「混乱战场」变成「有序流水线」。
|
设计模式 缓存 安全
Java设计模式的单例模式应用场景
Java设计模式的单例模式应用场景
251 4
|
12月前
|
设计模式 Java 数据库连接
Java编程中的设计模式:单例模式的深度剖析
【10月更文挑战第41天】本文深入探讨了Java中广泛使用的单例设计模式,旨在通过简明扼要的语言和实际示例,帮助读者理解其核心原理和应用。文章将介绍单例模式的重要性、实现方式以及在实际应用中如何优雅地处理多线程问题。
178 4
|
设计模式 安全 Java
Java 编程中的设计模式:单例模式的深度解析
【9月更文挑战第22天】在Java的世界里,单例模式就像是一位老练的舞者,轻盈地穿梭在对象创建的舞台上。它确保了一个类仅有一个实例,并提供全局访问点。这不仅仅是代码优雅的体现,更是资源管理的高手。我们将一起探索单例模式的奥秘,从基础实现到高级应用,再到它与现代Java版本的舞蹈,让我们揭开单例模式的面纱,一探究竟。
111 11

热门文章

最新文章