设计模式学习(24) 23-22 策略模式

文章目录

  • [0. 个人感悟](#0. 个人感悟)
  • [1. 概念](#1. 概念)
  • [2. 适配场景](#2. 适配场景)
    • [2.1 适合的场景](#2.1 适合的场景)
    • [2.2 常见场景举例](#2.2 常见场景举例)
  • [3. 实现方法](#3. 实现方法)
    • [3.1 实现思路](#3.1 实现思路)
    • [3.2 UML类图](#3.2 UML类图)
    • [3.3 代码示例](#3.3 代码示例)
  • [4. 优缺点](#4. 优缺点)
    • [4.1 优点](#4.1 优点)
    • [4.2 缺点](#4.2 缺点)
  • [5. 源码分析](#5. 源码分析)
    • [5.1 Java Collections框架中的Comparator](#5.1 Java Collections框架中的Comparator)

0. 个人感悟

  • 策略模式是很典型的设计模式,非常能突出编程思想:面向接口编程、隔离变化与不变、封装实现
  • 实际使用场景挺多,比如不同的支付策略、运维策略等
  • 策略模式和状态模式类图很像,但有着本质区别,使用场景不同
  • 当策略较多时,建议结合简单工厂模式,抽取策略工厂,将策略选取逻辑放到工厂,有利于职责单一

1. 概念

英文定义 (《设计模式:可复用面向对象软件的基础》)

Define a family of algorithms, encapsulate each one, and make them interchangealbe. Strategy lets the algorithm vary independently form clients that use it.

中文翻译

定义一系列算法,将每一个算法封装起来,并使它们可以相互替换。策略模式让算法独立于使用它的客户而变化。

理解

  • 将算法封装成独立的策略类,而不是将算法硬编码在客户端中
  • 客户端可以在运行时灵活选择不同的算法实现
  • 策略类实现相同的接口,可以无缝替换
  • 消除了大量的条件判断语句,使代码更清晰
  • 符合开闭原则,增加新策略无需修改现有代码

2. 适配场景

2.1 适合的场景

  1. 多种算法实现同一功能:当一个任务可以通过多种算法完成,且这些算法可能在不同场景下需要切换时
  2. 需要消除条件分支:当代码中存在大量if-else或switch-case语句来选择不同算法时
  3. 算法独立变化:当算法的实现可能会独立于使用它的客户端而变化时
  4. 运行时决策:当需要在运行时决定使用哪种算法时

2.2 常见场景举例

  1. 支付系统:多种支付方式(信用卡、PayPal、微信、支付宝)
  2. 排序算法:不同排序策略(快速排序、归并排序、堆排序)
  3. 压缩算法:不同压缩格式(ZIP、RAR、7Z、GZIP)
  4. 导航系统:不同路径规划策略(最短路径、最少时间、避开高速)
  5. 验证系统:不同验证方式(邮箱、手机、人脸识别)
  6. 折扣策略:不同促销活动(满减、折扣、返现)
  7. 数据导出:不同格式导出(CSV、PDF、Excel、JSON)

3. 实现方法

3.1 实现思路

  1. 识别系统中可能变化的部分,将其抽象为策略接口
  2. 为每个具体算法创建实现策略接口的类
  3. 创建上下文类,持有策略接口的引用
  4. 在上下文类中提供设置策略的方法
  5. 客户端根据需要创建具体策略对象并设置给上下文
  6. 上下文通过策略接口调用具体算法,而不知道具体实现细节

3.2 UML类图

角色说明

  • Context(上下文):持有一个Strategy对象的引用,并通过该接口调用具体算法
  • Strategy(策略接口):定义所有支持的算法的公共接口
  • ConcreteStrategy(具体策略):实现Strategy接口的具体算法类

3.3 代码示例

背景

已购物支付为例

  • 简化业务逻辑,支付策略可以是支付宝、微信,支持切换
    策略接口和实现类
java 复制代码
public interface PaymentStrategy {  
    /**  
     * @return designpattern.strategy.PayType 支付类型  
     * @description 获取支付类型,策略key  
     * @author bigHao  
     * @date 2026/1/28  
     **/    
     PayType getPayType();  
  
    /**  
     * @param amount 金额  
     * @description 支付  
     * @author bigHao  
     * @date 2026/1/28  
     **/    
     void pay(double amount);  
}

public class PayPalStrategy implements PaymentStrategy {  
    private String email;  
  
    public PayPalStrategy(String email) {  
        this.email = email;  
    }  
  
    @Override  
    public PayType getPayType() {  
        return PayType.PAY_PAL;  
    }  
  
    @Override  
    public void pay(double amount) {  
        System.out.println(STR."pay \{amount} using PayPal with email \{email}");  
    }  
}

public class WeChatPayStrategy implements PaymentStrategy {  
    private String weChatId;  
  
    public WeChatPayStrategy(String weChatId) {  
        this.weChatId = weChatId;  
    }  
  
    @Override  
    public PayType getPayType() {  
        return PayType.WECHAT_PAY;  
    }  
  
    @Override  
    public void pay(double amount) {  
        System.out.println(STR."pay \{amount} using WeChatPay with id \{weChatId}");  
    }  
}

策略工厂

java 复制代码
public class PayStrategyFactory {  
    public static Map<PayType, PaymentStrategy> map = new HashMap<PayType, PaymentStrategy>();  
  
    static {  
        PaymentStrategy aliPay = new PayPalStrategy("11111@ali.com");  
        PaymentStrategy weChatPay = new WeChatPayStrategy("weChatId001");  
        map.put(aliPay.getPayType(), aliPay);  
        map.put(weChatPay.getPayType(), weChatPay);  
    }  
  
  
    /**  
     * @param payType  
     * @return designpattern.strategy.PaymentStrategy 支付策略  
     * @description 获取策略  
     * @author bigHao  
     * @date 2026/1/28  
     **/    
     public static PaymentStrategy getPaymentStrategy(PayType payType) {  
        return map.get(payType);  
    }  
}

上下文

java 复制代码
public class ShoppingCart {  
    private double amount;  
  
    private PaymentStrategy strategy;  
  
    /**  
     * @description 结账  
     * @author bigHao  
     * @date 2026/1/28  
     **/    
     public void checkOut() {  
        strategy.pay(amount);  
    }  
  
    public double getAmount() {  
        return amount;  
    }  
  
    public void setAmount(double amount) {  
        this.amount = amount;  
    }  
  
    public PaymentStrategy getStrategy() {  
        return strategy;  
    }  
  
    public void setStrategy(PaymentStrategy strategy) {  
        this.strategy = strategy;  
    }  
}

辅助类

java 复制代码
public enum PayType {  
    PAY_PAL, // 支付宝  
    WECHAT_PAY // 微信  
}

测试

java 复制代码
public class Client {  
    static void main() {  
        // 初始化  
        ShoppingCart cart = new ShoppingCart();  
        cart.setAmount(100);  
  
        // 支付宝  
        cart.setStrategy(PayStrategyFactory.getPaymentStrategy(PayType.PAY_PAL));  
        cart.checkOut();  
  
        // 切换到微信  
        cart.setStrategy(PayStrategyFactory.getPaymentStrategy(PayType.WECHAT_PAY));  
        cart.checkOut();  
    }  
}

输出

复制代码
pay 100.0 using PayPal with email 11111@ali.com
pay 100.0 using WeChatPay with id weChatId001

4. 优缺点

4.1 优点

  1. 高内聚低耦合

    • 算法实现与使用分离,提高了内聚性
    • 上下文与具体策略解耦,降低了耦合度
  2. 开闭原则

    • 易于扩展新策略,无需修改现有代码
    • 支持在不修改上下文的情况下增加新算法
  3. 可读性

    • 消除了复杂的条件判断语句
    • 每个策略类职责单一,代码清晰
  4. 可维护性

    • 算法变化独立,修改一个策略不影响其他
    • 便于单元测试,每个策略可单独测试
  5. 复用性

    • 策略类可以在不同的上下文环境中复用
    • 避免了代码重复

4.2 缺点

  1. 策略类数量增加

    • 每个算法一个类,可能导致类数量膨胀
    • 需要权衡策略划分的粒度
  2. 客户端必须了解策略差异

    • 客户端需要知道不同策略的区别和适用场景
    • 增加了客户端的复杂性
  3. 对象创建开销

    • 频繁创建和销毁策略对象可能带来性能开销
    • 可考虑使用对象池或享元模式优化
  4. 策略间通信困难

    • 策略间相互独立,难以共享数据
    • 需要额外的通信机制

5. 源码分析

5.1 Java Collections框架中的Comparator

代码流程

java 复制代码
// java.util.Comparator接口就是策略模式的典型应用
public interface Comparator<T> {
    int compare(T o1, T o2);
}

// 具体策略:字符串长度比较器
public class StringLengthComparator implements Comparator<String> {
    @Override
    public int compare(String s1, String s2) {
        return Integer.compare(s1.length(), s2.length());
    }
}

// 上下文:Collections.sort()方法
public static <T> void sort(List<T> list, Comparator<? super T> c) {
    list.sort(c);
}

// 使用示例
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Collections.sort(names, new StringLengthComparator());

角色分析*

  • Strategy接口:Comparator
  • 具体策略:各种实现了Comparator的类,如StringLengthComparator
  • Context:Collections.sort()方法或List.sort()方法
  • 客户端:调用排序方法的代码

参考:

相关推荐
2601_949720261 小时前
flutter_for_openharmony手语学习app实战+手语识别实现
学习·flutter
浅念-2 小时前
C语言——内存函数
c语言·经验分享·笔记·学习·算法
●VON2 小时前
Flutter for OpenHarmony:基于 SharedPreferences 的本地化笔记应用架构与实现
笔记·学习·flutter·ui·架构·openharmony·von
求真求知的糖葫芦2 小时前
耦合传输线分析学习笔记(九)对称耦合微带线S参数矩阵推导与应用(下)
笔记·学习·矩阵·射频工程
herinspace2 小时前
管家婆分销软件中如何进行现金流量分配
运维·服务器·数据库·学习·电脑
LYS_06182 小时前
寒假学习(8)(c语言8+模数电8)
c语言·学习·pcb
AI浩2 小时前
学习语言驱动的序列级别模态不变表示用于视频可见光-红外行人重识别
学习·音视频
进阶小白猿2 小时前
Java技术八股学习Day26
java·开发语言·学习
我真的是大笨蛋2 小时前
MVCC解析
java·数据库·spring boot·sql·mysql·设计模式·设计规范