设计模式之策略模式：让你的代码灵活应对不同的算法 | 京东云技术团队
2023-10-17T11:27:13+08:00


作为一个程序员，我们经常会面临着在不同的情况下选择不同的算法来解决问题的需求。这种情况下，策略模式是一个非常有用的设计模式。在本文中，我将向你介绍策略模式的概念、结构以及如何应用这个模式来使你的代码更灵活。1.什么是策略模式？策略模式是一种行为型设计模式，它允许在运行时根据不同的情况选择算法的行为。这意味着我们可以将不同的算法封装成不同的策略类，并通过一个统一的接口来调用这些策略。2.策略模式的结构策略模式包括以下几个角色：上下文(Context)：持有一个策略对象的引用，并在需要时调用策略对象的方法。上下文可以根据具体情况选择不同的策略。策略(Strategy)：定义了一个公共接口，用于封装不同的算法。这个接口通常只有一个方法，即执行算法的方法。具体策略(ConcreteStrategy)：实现了策略接口，提供具体的算法实现。每个具体策略类都代表了一种特定的算法。策略模式的关键在于上下文持有一个策略对象的引用，并且通过调用策略对象的方法来执行具体的算法。这种方式使得上下文变得非常灵活，可以根据不同的需求在运行时切换算法。3.策略模式的应用场景策略模式适用于以下情况：当需要在运行时动态地选择算法实现时，可以使用策略模式。当一个类有多个行为变种，并且这些行为可以灵活地切换时，策略模式可以提供一种优雅的解决方案。例子（1）例如，在一个电商网站中，我们可能需要根据不同的支付方式来支付购物车的商品。可以是信用卡，当然也可以是京东支付、支付宝支付等等，这时，我们可以将每种支付行为封装成一个具体策略类，然后通过上下文选择合适的支付方式进行支付。也许你可能见过类似的代码if(payType==CreditCardType){
     System.out.println("使用信用卡支付：" + amount + " 元"); 
     // 实现具体的信用卡支付逻辑
}else if(payType==jdPayType){
     System.out.println("使用京东支付：" + amount + " 元"); 
     // 实现具体的京东支付逻辑
}else if(payType==alipayType){
    System.out.println("使用支付宝支付：" + amount + " 元"); 
    // 实现具体的支付宝支付逻辑 
}else{
    System.out.println("没实现,白嫖叭"); 
}好了，这时候微信一看，为啥没把微信支付加上，赶紧支持。研发小哥哥加班修改逻辑如下：if(payType==creditCardType){
     System.out.println("使用信用卡支付：" + amount + " 元"); 
     // 实现具体的信用卡支付逻辑
}else if(payType==jdPayType){
     System.out.println("使用京东支付：" + amount + " 元"); 
     // 实现具体的京东支付逻辑
}else if(payType==alipayType){
    System.out.println("使用支付宝支付：" + amount + " 元"); 
    // 实现具体的支付宝支付逻辑 
}else if(payType==wxPayType){ 
    System.out.println("使用微信支付：" + amount + " 元"); 
    // 实现具体的微信支付逻辑 
}else{
    System.out.println("没实现,白嫖叭"); 
}代码修改后，看着挺清晰明了，但是有一个问题，如果之后还有其他如抖音支付、乱七八糟支付的话我们就要一直修改这个类，一直添加 ...else if...很明显违背了面向对象设计的六大原则之二：单一职责、开闭原则（对扩展开放、对修改关闭），六个违背俩，这活没法干了！下面演示了如何使用策略模式来实现不同的支付方式：// 定义一个支付的策略接口
public interface PaymentStrategy {
    //这只是个测试场景，真实场景下应该没人用double类型叭
    void pay(double amount);
}

// 具体策略实现
// 信用卡支付
public class CreditCardPaymentStrategy implements PaymentStrategy {
    public void pay(double amount) {
        System.out.println("使用信用卡支付：" + amount + " 元");
        // 实现具体的信用卡支付逻辑
    }
}
// 京东支付
public class JdPaymentStrategy implements PaymentStrategy {
    public void pay(double amount) {
       System.out.println("使用京东支付：" + amount + " 元"); 
       // 实现具体的京东支付逻辑
    }
}
//省略...
// 支付宝支付
// 微信支付


// 上下文
public class ShoppingCart {
    private PaymentStrategy paymentStrategy;

    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

    public void checkout(double amount) {
        // 调用策略对象的支付方法
        paymentStrategy.pay(amount);
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();
        
        // 设置使用信用卡支付策略
        cart.setPaymentStrategy(new CreditCardPaymentStrategy());
        cart.checkout(1000.00);

        // 设置使用jd支付策略
        cart.setPaymentStrategy(new JdPaymentStrategy());
        cart.checkout(2000.00);
        //如果还想用其他支付 就继续写啊
       
    }
}

在上面的例子中，PaymentStrategy是策略接口，CreditCardPaymentStrategy和PayPalPaymentStrategy是具体的策略实现。ShoppingCart是上下文，通过setPaymentStrategy方法来设置不同的支付策略，并通过checkout方法调用具体策略的支付方法。看看，是不是可以通过扩展来增加支付方式。每个子类只实现具体的某种支付的策略。例子（2）实现一个简单的计算器（整数），简单想一想也许涉及以下几种计算方式：加减乘除，也许有人会这样实现，但是我想一定不是你，聪明的你应该已经学会了策略模式在这种场景下的应用试想 如果我想增加取余操作呢？
int num1 = 10;
int num2 = 5;
String operator = "+";

if (operator.equals("+")) {
    int result = num1 + num2;
    System.out.println("加法结果：" + result);
} else if (operator.equals("-")) {
     int result = num1 - num2;
      System.out.println("减法结果：" + result);
} else if (operator.equals("*")) {
     int result = num1 * num2;
     System.out.println("乘法结果：" + result);
} else if (operator.equals("/")) {
     if (num2 != 0) {
          int result = num1 / num2;
          System.out.println("除法结果：" + result);
     } else {
          System.out.println("除数不能为零");
     }
 } else {
     System.out.println("无效的运算符");
 }


4.总结策略模式是一种灵活、可扩展的设计模式，它通过将算法封装成策略类来实现不同的行为变种。使用策略模式可以提高代码的可维护性和复用性，同时也符合面向对象设计的原则。希望本文的介绍对你理解策略模式有所帮助，也希望你能在实际项目中运用到这个强大的设计模式！作者：京东零售 闫先东来源：京东云开发者社区 转载请注明来源