1

前言:

在我们日常的开发中,我们往往会遇到如下问题: 在一个类中需要根据不同的情况选择不同的行为时,我们可能会使用大量的条件判断(如 if-else 或 switch-case)。这种做法虽然也可以,但当需求扩展或变动时,会引发以下问题:

  1. 高耦合:条件判断将行为与业务逻辑紧密绑定在一起,导致代码变得难以修改和扩展。
  2. 低可维护性:每次添加新的行为或变化时,我们都需要修改原有的类,导致代码出现不必要的重复和冗余。
  3. 难以测试:由于多个行为被紧密耦合在一起,单独测试某一算法变得复杂。

为了解决这些问题,策略设计模式应运而生。它允许将行为封装到独立的策略类中,从而使得系统的各个部分相对独立,能够单独修改、替换和扩展。

策略设计模式的实现

在策略设计模式中,我们通常会定义一个通用的策略接口,所有具体的策略类都会实现这个接口,然后,我们在上下文类中持有一个对策略接口的引用,并通过设置不同的策略对象来动态改变行为。

不使用策略设计模式案例

考虑一个电子商务系统,其中用户可以选择不同的支付方式:信用卡支付、支付宝支付、微信支付。如果我们没有使用策略设计模式,可能会写出类似下面的实现:

流程图:

flowchart TD
    A[开始结账] --> B{支付方式}
    B -->|信用卡| C["输出: 使用信用卡支付 X 元"]
    B -->|支付宝| D["输出: 使用支付宝支付 X 元"]
    B -->|微信支付| E["输出: 使用微信支付 X 元"]
    B -->|其他方式| F["输出: 未选择有效支付方式"]
    C --> G[结束]
    D --> G
    E --> G
    F --> G

使用示例

  1. ShoopingCart 类
public class ShoppingCart {
    private String paymentMethod;

    public ShoppingCart(String paymentMethod) {
        this.paymentMethod = paymentMethod;
    }

    public void checkout(int amount) {
        if (paymentMethod.equals("CreditCard")) {
            System.out.println("使用信用卡支付 " + amount + " 元。");
        } else if (paymentMethod.equals("AliPay")) {
            System.out.println("使用支付宝支付 " + amount + " 元。");
        } else if (paymentMethod.equals("WeChatPay")) {
            System.out.println("使用微信支付 " + amount + " 元。");
        } else {
            System.out.println("未选择有效的支付方式。");
        }
    }
}

checkout 方法:这个方法模拟结账操作。它根据 paymentMethod 的值来判断使用哪种支付方式。它的逻辑如下:

  • 如果支付方式是 CreditCard,则打印使用信用卡支付的提示。
  • 如果支付方式是 AliPay,则打印使用支付宝支付的提示。
  • 如果支付方式是 WeChatPay,则打印使用微信支付的提示。
  • 如果支付方式是其他的字符串,打印 "未选择有效的支付方式." 提示无效支付方式。

执行代码

public class SpiApplication {

    public static void main(String[] args) {
        // 创建使用信用卡支付的购物车
        ShoppingCart cart1 = new ShoppingCart("CreditCard");
        cart1.checkout(1000); 

        // 创建使用支付宝支付的购物车
        ShoppingCart cart2 = new ShoppingCart("AliPay");
        cart2.checkout(500); 

        // 创建使用微信支付的购物车
        ShoppingCart cart3 = new ShoppingCart("WeChatPay");
        cart3.checkout(750); 

        // 创建使用无效支付方式的购物车
        ShoppingCart cart4 = new ShoppingCart("PayPal");
        cart4.checkout(300); 
    }
}

输出结果

使用信用卡支付 1000 元。
使用支付宝支付 500 元。
使用微信支付 750 元。
未选择有效的支付方式。

存在的问题

扩展困难:每当我们需要增加新的支付方式时,都需要修改 ShoppingCart 类,增加新的条件判断。这个操作违背了开闭原则(对修改关闭,对扩展开放)。
维护难度大:随着支付方式的增多,ShoppingCart 类会变得越来越庞大,难以维护。
缺乏灵活性:如果用户希望在运行时选择不同的支付方式,我们的代码很难做到动态切换。

假设我们要为 ShoppingCart 类添加一个新的支付方式——CloudQuickPass,即“云闪付”。我们需要在 ShoppingCart 类中增加一个新的 else if 条件判断,如下所示:

扩展后的 ShoppingCart 类:

 public void checkout(int amount) {
        if (paymentMethod.equals("CreditCard")) {
            System.out.println("使用信用卡支付 " + amount + " 元。");
        } else if (paymentMethod.equals("CloudQuickPass")) {
             System.out.println("使用云闪付支付 " + amount + " 元。");
        } xxx
    }

增加后的流程图

flowchart TD
    A[开始结账] --> B{支付方式}
    B -->|信用卡| C["输出: 使用信用卡支付 X 元"]
    B -->|支付宝| D["输出: 使用支付宝支付 X 元"]
    B -->|微信支付| E["输出: 使用微信支付 X 元"]
    B -->|云闪付| F["输出: 使用云闪付支付 X 元"]
    B -->|其他方式| G["输出: 未选择有效支付方式"]
    C --> H[结束]
    D --> H
    E --> H
    F --> H
    G --> H

使用策略设计模式案例

引入策略模式后,我们将每一种支付方式抽成一个独立的策略类,并在 ShoppingCart 中设置不同的策略对象来决定支付对象:

classDiagram
    %% 定义接口和类
    class PaymentStrategy {
        <<interface>>
        +pay(int amount) void
    }

    class CreditCardPayment {
        +pay(int amount) void
    }

    class AliPayPayment {
        +pay(int amount) void
    }

    class WeChatPayPayment {
        +pay(int amount) void
    }

    %% 实现关系
    CreditCardPayment --|> PaymentStrategy : implements
    AliPayPayment --|> PaymentStrategy : implements
    WeChatPayPayment --|> PaymentStrategy : implements

使用案例

  1. PaymentStrategy 接口
public interface PaymentStrategy {
    void pay(int amount);
}
  1. 具体支付策略接口
// 具体支付策略

// 信用卡支付实现
public class CreditCardPayment implements PaymentStrategy {
    @Override
    public void pay(int amount) {
        System.out.println("使用信用卡支付 " + amount + " 元。");
    }
}

// 支付宝支付实现
public class AliPayPayment implements PaymentStrategy {
    @Override
    public void pay(int amount) {
        System.out.println("使用支付宝支付 " + amount + " 元。");
    }
}

// 微信支付实现
public class WeChatPayPayment implements PaymentStrategy {
    @Override
    public void pay(int amount) {
        System.out.println("使用微信支付 " + amount + " 元。");
    }
}
  1. 修改 ShoopingCart 类
public class ShoppingCart {
    private PaymentStrategy paymentStrategy;

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

    public void checkout(int amount) {
        if (paymentStrategy == null) {
            System.out.println("未选择有效的支付方式");
            return;
        }
        paymentStrategy.pay(amount);
    }
}

执行代码

public class SpiApplication {

    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();

        // 用户选择使用信用卡支付
        cart.setPaymentStrategy(new CreditCardPayment());
        cart.checkout(1000);

        // 用户选择使用支付宝支付
        cart.setPaymentStrategy(new AliPayPayment());
        cart.checkout(500);

        // 用户选择使用微信支付
        cart.setPaymentStrategy(new WeChatPayPayment());
        cart.checkout(750);
    }
}

输出结果

使用信用卡支付 1000 元。
使用支付宝支付 500 元。
使用微信支付 750 元。

使用策略者设置模型扩展 CloudQuickPass,即“云闪付”。

增加一个实现类

// 云闪付支付
public class CloudQuickPassPayment implements PaymentStrategy {
    @Override
    public void pay(int amount) {
        System.out.println("使用云闪付支付 " + amount + " 元。");
    }
}

此时关系图

classDiagram
    %% 定义接口和类
    class PaymentStrategy {
        <<interface>>
        +pay(int amount) void
    }

    class CreditCardPayment {
        +pay(int amount) void
    }

    class AliPayPayment {
        +pay(int amount) void
    }

    class WeChatPayPayment {
        +pay(int amount) void
    }

    class CloudQuickPassPayment {
        +pay(int amount) void
    }

    %% 实现关系
    CreditCardPayment --|> PaymentStrategy : implements
    AliPayPayment --|> PaymentStrategy : implements
    WeChatPayPayment --|> PaymentStrategy : implements
    CloudQuickPassPayment --|> PaymentStrategy : implements

总结

使用策略者模式之后,扩展新的支付方式不再需要修改现有的 ShoppingCart 类,也不再需要增加条件判断,每一次增加的支付方式的时候,我们只需要创建一个新的策略类,并注入到 ShoppingCart 中。


kexb
583 声望27 粉丝

引用和评论

0 条评论