策略模式:算法切换的超级武器🚀,让代码灵活如风!



前言:为什么需要策略模式?🤔

各位宝子们,今天我们来聊一个设计模式界的"算法大师"——策略模式!😎 还在为大量的if-else判断而头疼吗?还在为算法的频繁变更而烦恼吗?策略模式来拯救你啦!

策略模式是设计模式家族中的"行为型专家",它能帮我们优雅地管理算法族,让代码更加灵活、可扩展。今天就带大家彻底搞懂这个"看似简单,实则强大"的设计模式!💯


一、策略模式:算法切换的专业户 🎯

1.1 什么是策略模式?

策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,把它们一个个封装起来,并且使它们可相互替换。就像现实生活中的出行方式一样,你可以选择步行、骑车、开车或坐地铁,每种方式都是一种策略,你可以根据情况灵活选择!🚗

1.2 为什么需要策略模式?

想象一下这些场景:

  • 需要在运行时动态选择算法
  • 有多种方式实现同一个功能
  • 避免使用大量的条件判断语句
  • 需要隐藏算法的具体实现细节
  • 算法经常变化,需要易于扩展

这些场景有什么共同点?它们都涉及到算法的选择和切换问题。策略模式就是为这些场景量身定制的!🚀


二、策略模式的结构与实现 🧩

2.1 策略模式的核心结构

策略模式包含以下几个关键角色:

  • 策略接口(Strategy):定义所有具体策略的通用接口
  • 具体策略(ConcreteStrategy):实现策略接口的具体算法
  • 上下文(Context):持有一个策略的引用,并将工作委托给策略对象
// 策略接口
public interface Strategy {
    int execute(int a, int b);
}

// 具体策略:加法
public class AddStrategy implements Strategy {
    @Override
    public int execute(int a, int b) {
        System.out.println("执行加法运算");
        return a + b;
    }
}

// 具体策略:减法
public class SubtractStrategy implements Strategy {
    @Override
    public int execute(int a, int b) {
        System.out.println("执行减法运算");
        return a - b;
    }
}

// 具体策略:乘法
public class MultiplyStrategy implements Strategy {
    @Override
    public int execute(int a, int b) {
        System.out.println("执行乘法运算");
        return a * b;
    }
}

// 上下文
public class Calculator {
    private Strategy strategy;
    
    public Calculator(Strategy strategy) {
        this.strategy = strategy;
    }
    
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }
    
    public int calculate(int a, int b) {
        return strategy.execute(a, b);
    }
}

// 客户端代码
Calculator calculator = new Calculator(new AddStrategy());
int result1 = calculator.calculate(10, 5); // 输出:执行加法运算,结果:15

calculator.setStrategy(new MultiplyStrategy());
int result2 = calculator.calculate(10, 5); // 输出:执行乘法运算,结果:50

2.2 策略模式的工作流程

  1. 客户端创建具体策略对象
  2. 将策略对象传递给上下文
  3. 上下文将工作委托给策略对象
  4. 策略对象执行具体算法
  5. 可以在运行时动态切换策略

三、策略模式的实际应用案例 🌟

3.1 支付系统

电商系统中的支付方式选择是策略模式的经典应用。用户可以选择支付宝、微信、银行卡等不同的支付方式。

// 支付策略接口
public interface PaymentStrategy {
    boolean pay(double amount);
    String getPaymentType();
}

// 支付宝支付策略
public class AlipayStrategy implements PaymentStrategy {
    private String account;
    
    public AlipayStrategy(String account) {
        this.account = account;
    }
    
    @Override
    public boolean pay(double amount) {
        System.out.println("使用支付宝账户 " + account + " 支付 " + amount + " 元");
        // 模拟支付逻辑
        return true;
    }
    
    @Override
    public String getPaymentType() {
        return "支付宝";
    }
}

// 微信支付策略
public class WechatPayStrategy implements PaymentStrategy {
    private String openId;
    
    public WechatPayStrategy(String openId) {
        this.openId = openId;
    }
    
    @Override
    public boolean pay(double amount) {
        System.out.println("使用微信账户 " + openId + " 支付 " + amount + " 元");
        // 模拟支付逻辑
        return true;
    }
    
    @Override
    public String getPaymentType() {
        return "微信支付";
    }
}

// 银行卡支付策略
public class BankCardStrategy implements PaymentStrategy {
    private String cardNumber;
    private String cvv;
    
    public BankCardStrategy(String cardNumber, String cvv) {
        this.cardNumber = cardNumber;
        this.cvv = cvv;
    }
    
    @Override
    public boolean pay(double amount) {
        System.out.println("使用银行卡 " + cardNumber + " 支付 " + amount + " 元");
        // 模拟支付逻辑
        return true;
    }
    
    @Override
    public String getPaymentType() {
        return "银行卡";
    }
}

// 支付上下文
public class PaymentContext {
    private PaymentStrategy paymentStrategy;
    
    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }
    
    public boolean executePayment(double amount) {
        if (paymentStrategy == null) {
            System.out.println("请选择支付方式");
            return false;
        }
        
        System.out.println("选择的支付方式:" + paymentStrategy.getPaymentType());
        return paymentStrategy.pay(amount);
    }
}

// 使用示例
PaymentContext paymentContext = new PaymentContext();

// 使用支付宝支付
paymentContext.setPaymentStrategy(new AlipayStrategy("user@alipay.com"));
paymentContext.executePayment(100.0);

// 切换到微信支付
paymentContext.setPaymentStrategy(new WechatPayStrategy("wx123456"));
paymentContext.executePayment(200.0);

3.2 排序算法选择

根据数据量的大小选择不同的排序算法,这也是策略模式的典型应用。

// 排序策略接口
public interface SortStrategy {
    void sort(int[] array);
    String getAlgorithmName();
}

// 冒泡排序策略
public class BubbleSortStrategy implements SortStrategy {
    @Override
    public void sort(int[] array) {
        System.out.println("使用冒泡排序");
        int n = array.length;
        for (int i = 0; i < n - 1; i++) {
            for (int j = 0; j < n - i - 1; j++) {
                if (array[j] > array[j + 1]) {
                    // 交换元素
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
            }
        }
    }
    
    @Override
    public String getAlgorithmName() {
        return "冒泡排序";
    }
}

// 快速排序策略
public class QuickSortStrategy implements SortStrategy {
    @Override
    public void sort(int[] array) {
        System.out.println("使用快速排序");
        quickSort(array, 0, array.length - 1);
    }
    
    private void quickSort(int[] array, int low, int high) {
        if (low < high) {
            int pi = partition(array, low, high);
            quickSort(array, low, pi - 1);
            quickSort(array, pi + 1, high);
        }
    }
    
    private int partition(int[] array, int low, int high) {
        int pivot = array[high];
        int i = (low - 1);
        
        for (int j = low; j < high; j++) {
            if (array[j] <= pivot) {
                i++;
                int temp = array[i];
                array[i] = array[j];
                array[j] = temp;
            }
        }
        
        int temp = array[i + 1];
        array[i + 1] = array[high];
        array[high] = temp;
        
        return i + 1;
    }
    
    @Override
    public String getAlgorithmName() {
        return "快速排序";
    }
}

// 排序上下文
public class SortContext {
    private SortStrategy sortStrategy;
    
    public void setSortStrategy(SortStrategy sortStrategy) {
        this.sortStrategy = sortStrategy;
    }
    
    public void performSort(int[] array) {
        if (sortStrategy == null) {
            System.out.println("请选择排序算法");
            return;
        }
        
        System.out.println("选择的排序算法:" + sortStrategy.getAlgorithmName());
        long startTime = System.currentTimeMillis();
        sortStrategy.sort(array);
        long endTime = System.currentTimeMillis();
        System.out.println("排序完成,耗时:" + (endTime - startTime) + "ms");
    }
    
    // 智能选择排序算法
    public void smartSort(int[] array) {
        if (array.length < 100) {
            setSortStrategy(new BubbleSortStrategy());
        } else {
            setSortStrategy(new QuickSortStrategy());
        }
        performSort(array);
    }
}

3.3 促销活动策略

电商系统中的促销活动也是策略模式的好例子,不同的促销策略可以灵活切换。

// 促销策略接口
public interface PromotionStrategy {
    double calculateDiscount(double originalPrice);
    String getPromotionName();
}

// 满减策略
public class FullReductionStrategy implements PromotionStrategy {
    private double threshold;
    private double reduction;
    
    public FullReductionStrategy(double threshold, double reduction) {
        this.threshold = threshold;
        this.reduction = reduction;
    }
    
    @Override
    public double calculateDiscount(double originalPrice) {
        if (originalPrice >= threshold) {
            return originalPrice - reduction;
        }
        return originalPrice;
    }
    
    @Override
    public String getPromotionName() {
        return "满" + threshold + "减" + reduction;
    }
}

// 打折策略
public class DiscountStrategy implements PromotionStrategy {
    private double discountRate;
    
    public DiscountStrategy(double discountRate) {
        this.discountRate = discountRate;
    }
    
    @Override
    public double calculateDiscount(double originalPrice) {
        return originalPrice * discountRate;
    }
    
    @Override
    public String getPromotionName() {
        return (int)((1 - discountRate) * 10) + "折";
    }
}

// 促销上下文
public class PromotionContext {
    private PromotionStrategy promotionStrategy;
    
    public void setPromotionStrategy(PromotionStrategy promotionStrategy) {
        this.promotionStrategy = promotionStrategy;
    }
    
    public double calculateFinalPrice(double originalPrice) {
        if (promotionStrategy == null) {
            System.out.println("无促销活动,原价销售");
            return originalPrice;
        }
        
        double finalPrice = promotionStrategy.calculateDiscount(originalPrice);
        System.out.println("促销活动:" + promotionStrategy.getPromotionName());
        System.out.println("原价:" + originalPrice + ",优惠后:" + finalPrice);
        return finalPrice;
    }
}

四、策略模式的优缺点 ⚖️

4.1 优点

  • 算法可以自由切换:可以在运行时动态选择算法
  • 避免使用多重条件判断:消除大量的if-else或switch-case语句
  • 扩展性良好:增加新算法只需要实现策略接口
  • 符合开闭原则:对扩展开放,对修改关闭
  • 提高算法的保密性和安全性:算法实现细节被封装

4.2 缺点

  • 策略类数量增多:每个算法都需要一个策略类
  • 客户端必须知道所有策略:客户端需要了解各种策略的区别
  • 增加了对象的数目:每个策略都是一个对象

五、策略模式与其他模式的区别 🔍

5.1 策略模式 vs 状态模式

虽然结构相似,但意图不同:

  • 策略模式:关注算法的互换,客户端主动选择策略
  • 状态模式:关注对象状态的变化,状态转换通常是自动的

5.2 策略模式 vs 工厂模式

  • 策略模式:关注算法的选择和执行
  • 工厂模式:关注对象的创建

5.3 策略模式 vs 命令模式

  • 策略模式:封装算法,关注"怎么做"
  • 命令模式:封装请求,关注"做什么"

六、何时使用策略模式?🎯

以下场景适合使用策略模式:

  1. 需要在运行时动态选择算法
  2. 有多种方式实现同一个功能
  3. 存在大量的条件判断语句
  4. 算法经常变化,需要易于扩展
  5. 需要隐藏算法的实现细节

七、策略模式的最佳实践 💡

7.1 结合工厂模式

// 策略工厂
public class StrategyFactory {
    private static final Map<String, PaymentStrategy> strategies = new HashMap<>();
    
    static {
        strategies.put("alipay", new AlipayStrategy("default@alipay.com"));
        strategies.put("wechat", new WechatPayStrategy("default_openid"));
        strategies.put("bankcard", new BankCardStrategy("1234567890", "123"));
    }
    
    public static PaymentStrategy getStrategy(String type) {
        return strategies.get(type.toLowerCase());
    }
}

7.2 使用枚举实现策略

public enum CalculationStrategy {
    ADD {
        @Override
        public int execute(int a, int b) {
            return a + b;
        }
    },
    SUBTRACT {
        @Override
        public int execute(int a, int b) {
            return a - b;
        }
    },
    MULTIPLY {
        @Override
        public int execute(int a, int b) {
            return a * b;
        }
    };
    
    public abstract int execute(int a, int b);
}

总结:策略模式的精髓 💎

策略模式的核心思想是将算法的定义、创建和使用分离。这种设计使得我们可以:

  1. 在运行时动态选择算法
  2. 避免复杂的条件判断逻辑
  3. 轻松扩展新的算法
  4. 提高代码的可维护性和可测试性

策略模式就像是给程序安装了一个"算法切换器",让你能够根据不同的情况选择最合适的算法,而不需要修改现有代码。这就是策略模式的魅力所在!✨

记住,当你的代码中出现大量的if-else判断来选择不同算法时,考虑一下策略模式,它可能是你的最佳选择!💪


各位宝子们,策略模式的精髓就是这样啦!希望这篇文章能帮助你理解并应用这个实用的设计模式。如果有任何问题,欢迎在评论区留言讨论!下期见!👋

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐