【设计模式】一文速通策略模式

87 阅读3分钟

1. 引入

假设现在要设计一个支付系统,需要支持三种支付方式:

  • 微信支付
  • 支付宝支付
  • 银行卡支付

针对不同的支付方式,有不同的支付逻辑,以下是两种设计方案。

1.1 方案一:if-else实现

1.1.1 实现代码

public class PaymentApp {
    public static void main(String[] args) {
    
      String payment = "";
      Double amount = 100.0;
      if(payment = "AliPay"){
        // 使用支付宝支付
        payWithAliPay(amount);
      }
       if(payment = "WeChatPay"){
         // 使用微信支付
        payWithWeChatPay(amount);
      }
      if(payment = "CreditCard"){
        // 使用信用卡支付
        payWithCreditCard("1234567890123456", "123", amount);
      }
    }


    public static void payWithAliPay(double amount) {
        System.out.println("使用支付宝支付,金额为:" + amount);
        // 支付宝实际支付逻辑
    }


    public static void payWithWeChatPay(double amount) {
        System.out.println("使用微信支付,金额为: " + amount);
        // 微信实际支付逻辑
    }


    public static void payWithCreditCard(String cardNumber, String cvv, double amount) {
        System.out.println("使用信用卡支付:" + cardNumber.substring(cardNumber.length() - 4) + "金额为: " + amount);
        // 信用卡实际支付逻辑
    }
}

1.1.2 上述方案存在问题

  • 代码臃肿:随着支付方式增多,要写多条if-else语句,导致代码的可读性较差,且难以维护;

  • 违背了开闭原则:如果每次新增或者修改支付方式,都需要修改代码;

  • 复用性差:支付逻辑无法复用。

1.2 使用策略模式实现

1.2.1 实现代码

  • 定义策略接口PaymentStrategy
// 策略接口
public interface PaymentStrategy {
    void pay(double amount);
}
  • 实现具体策略类
// 支付宝支付策略
public class AliPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("使用支付宝支付,金额为:" + amount);
        // 实际支付逻辑
    }
}
// 微信支付策略
public class WeChatPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("使用微信支付,金额为:" + amount);
        // 实际支付逻辑
    }
}
// 信用卡支付策略
public class CreditCardPayStrategy implements PaymentStrategy {
    private String cardNumber;
    private String cvv;


    public CreditCardPayStrategy(String cardNumber, String cvv) {
        this.cardNumber = cardNumber;
        this.cvv = cvv;
    }


    @Override
    public void pay(double amount) {
        System.out.println("Paid using Credit Card ending with " + cardNumber.substring(cardNumber.length() - 4) + ": $" + amount);
        // 实际支付逻辑
    }
}
  • 定义上下文类PaymentContext
// 上下文类
public class PaymentContext {
    private PaymentStrategy paymentStrategy;


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


    public void performPayment(double amount) {
        if (paymentStrategy == null) {
            throw new IllegalStateException("Payment strategy is not set.");
        }
        paymentStrategy.pay(amount);
    }
}

image.png

1.2.2 上述方案优点

  • 算法的实现与使用逻辑隔离;

  • 符合开闭原则

2. 策略模式

2.1 定义

策略模式(Strategy Pattern)/ 政策模式(Policy Pattern:一种行为设计模式,能定义一系列算法,并将每种算法分别放入独立的类中,以使算法的对象能够相互替换。

【例如】如果想要去往机场,可以根据自己的实际情况选择适合自己的出行策略。 image.png

2.2 角色及结构

2.2.1 策略模式三大角色

  • Context上下文角色:承上启下的封装作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化;

  • Strategy抽象策略角色:定义每个策略或算法必须有的方法和属性;

  • ConcreteStrategy具体策略角色:实现抽象策略中的操作,定义具体的算法实现逻辑

2.2.2 结构

image.png

2.3 适用场景

  • 多个类只有在算法或行为稍有不同

  • 算法需要自由切换

  • 算法在上下文的逻辑中不是特别重要,使用策略模式能将类的业务逻辑和算法实现细节隔离;

2.4 优缺点

2.4.1 优点

  • 算法可以自由切换

  • 避免使用多重条件判断

  • 可以将算法的实现使用算法的代码隔离

  • 扩展性良好:系统新增策略只需要实现接口,不需要修改其他代码,符合开闭原则。

2.4.2 缺点

  • 策略数量增多:每一个策略都是一个类,复用可能性较小;

  • 所有策略类都要对外暴露:上层模块必须知道有哪些策略才能决定使用哪一个策略。

2.5 注意事项

如果系统中的一个策略家族的具体策略数量超过4个,需要考虑混合模式,用于解决策略类膨胀和对外暴露的问题,否则日后的系统维护工作比较难。

参考资料