【设计模式】(21)策略模式


策略模式(Strategy Pattern)教程


一、模式定义

策略模式定义一系列算法族,将每个算法封装成独立类,并使它们可以相互替换
核心目标:解耦算法的定义与使用,使算法能独立于客户端变化,消除复杂的条件判断。


二、适用场景

  1. 多算法切换:系统需要在多种算法中动态选择(如排序、加密、压缩算法)。
  2. 替代条件分支:消除代码中大量的 if-elseswitch-case 语句。
  3. 扩展性需求:需要灵活添加新算法而不影响已有代码。
  4. 算法复用:多个类共享相同算法的不同实现。

典型应用

  • 支付方式选择(支付宝、微信、信用卡)。
  • 导航策略(最短路径、最快路径、避开高速)。
  • 数据格式化(JSON、XML、CSV)。

三、模式结构

角色说明
  1. 策略接口(Strategy)
    定义算法的公共接口(如 execute())。
  2. 具体策略(Concrete Strategy)
    实现策略接口的具体算法类。
  3. 上下文类(Context)
    持有策略对象的引用,负责调用策略算法,可动态切换策略。

四、代码案例

案例1:支付系统策略

根据用户选择调用不同的支付方式。

步骤1:定义策略接口
public interface PaymentStrategy {
    void pay(double amount);
}
步骤2:实现具体策略
// 支付宝支付
public class AlipayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.printf("支付宝支付:%.2f元\n", amount);
    }
}

// 微信支付
public class WechatPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.printf("微信支付:%.2f元\n", amount);
    }
}

// 信用卡支付
public class CreditCardStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.printf("信用卡支付:%.2f元\n", amount);
    }
}
步骤3:实现上下文类
public class PaymentContext {
    private PaymentStrategy strategy;

    public void setStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    public void executePayment(double amount) {
        if (strategy != null) {
            strategy.pay(amount);
        } else {
            System.out.println("请选择支付方式");
        }
    }
}
步骤4:客户端使用
public class Client {
    public static void main(String[] args) {
        PaymentContext context = new PaymentContext();
        
        // 用户选择支付宝
        context.setStrategy(new AlipayStrategy());
        context.executePayment(100.50);  // 输出:支付宝支付:100.50元
        
        // 切换为微信支付
        context.setStrategy(new WechatPayStrategy());
        context.executePayment(200.00);  // 输出:微信支付:200.00元
    }
}

案例2:数据压缩策略

动态选择压缩算法(ZIP、RAR、7z)。

步骤1:策略接口与实现
public interface CompressionStrategy {
    void compress(String file);
}

public class ZipStrategy implements CompressionStrategy {
    @Override
    public void compress(String file) {
        System.out.println("使用ZIP压缩:" + file);
    }
}

public class RarStrategy implements CompressionStrategy {
    @Override
    public void compress(String file) {
        System.out.println("使用RAR压缩:" + file);
    }
}
步骤2:上下文类
public class CompressionContext {
    private CompressionStrategy strategy;

    public void setStrategy(CompressionStrategy strategy) {
        this.strategy = strategy;
    }

    public void compressFile(String file) {
        strategy.compress(file);
    }
}
步骤3:客户端调用
public class Client {
    public static void main(String[] args) {
        CompressionContext context = new CompressionContext();
        context.setStrategy(new ZipStrategy());
        context.compressFile("data.csv");  // 输出:使用ZIP压缩:data.csv
    }
}

五、策略模式 vs 工厂模式

对比项 策略模式 工厂模式
核心目标 动态切换算法 创建对象
关注点 行为(如何做) 创建(谁来创建)
对象关系 上下文持有策略对象 工厂生产对象
典型应用 支付方式、压缩算法 数据库连接、日志记录器

六、常见问题

  1. 如何管理策略对象的创建?

    • 结合工厂模式或依赖注入框架(如Spring)管理策略实例。
  2. 策略模式是否会导致类数量增加?

    • 是的,但每个策略类职责单一,符合单一职责原则。
  3. 如何选择默认策略?

    • 在上下文中初始化默认策略,或由客户端显式设置。
  4. 策略模式如何支持算法参数传递?

    • 在策略接口方法中定义参数(如 execute(data))。

七、习题练习

基础题

实现一个 计算器,支持加减乘除策略的动态切换。

提高题

设计一个 文件上传系统,支持根据网络状况动态切换上传策略(普通上传、分块上传、断点续传)。

思考题

在微服务架构中,如何结合策略模式实现不同服务间的容错机制(如重试、熔断、降级)?


八、推荐拓展

  1. 框架级应用

    • Java Comparator 接口:通过策略模式实现自定义排序规则。
    • Spring ResourceLoader:根据策略加载不同资源(类路径、文件系统、URL)。
  2. 设计模式组合

    • 结合策略模式与模板方法模式,定义算法骨架并允许步骤自定义。
    • 结合策略模式与装饰器模式,动态叠加算法功能。
  3. 性能优化

    • 使用享元模式共享无状态策略对象。
    • 通过缓存频繁使用的策略实例减少对象创建开销。
  4. 实际项目应用

    • 电商促销系统(满减、折扣、赠品等优惠策略)。
    • 机器学习模型选择(根据不同数据特征选择最佳算法)。

通过本教程,你可以掌握策略模式在算法管理和动态切换中的核心技巧,并能够灵活应用于需要多方案选择的业务场景。若有疑问或需要代码调试,欢迎随时交流!

你可能感兴趣的:(Java教程,设计模式,策略模式)