Spring项目中使用策略模式和工厂模式

不同类型的数据对应不同的处理的情况,自己经常以下边的方式处理,个人感觉扩展性也比较强,做个记录。

下边以多种支付类型做示例

假如当前系统支持微信支付和支付宝支付

示例

  1. 定义支付类型枚举,方便统一管理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    public enum PayEnum {

    /**
    * 微信支付
    */
    WX(1, "wx"),

    /**
    * 支付宝支付
    */
    ALIPAY(2, "alipay");

    private final int code;
    private final String en;

    PayEnum(int code, String en) {
    this.code = code;
    this.en = en;
    }

    public int getCode() {
    return code;
    }

    public String getEn() {
    return en;
    }

    /**
    * 方便通过code来获取枚举类型
    *
    * @param code
    * @return
    */
    public static PayEnum getByCode(int code) {
    for (PayEnum value : values()) {
    if (value.getCode() == code) {
    return value;
    }
    }
    return null;
    }
    }
  2. 定义一个支付处理类PayService

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    /**
    * PayService
    *
    * @author ZXP
    * @date 2021/12/4 21:23
    */
    public interface PayService {

    /**
    * 支持的支付类型
    *
    * @return
    */
    PayEnum getPayType();

    /**
    * 具体的支付逻辑
    *
    * @param obj
    */
    void pay(Object obj);
    }
  3. 两个实现类WxPayServiceImplAliPayServiceImpl,分别对应处理微信支付和支付宝支付,别忘了加**@Service**注解(@Component也一样)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    /**
    * 微信支付处理类
    *
    * @author ZXP
    * @date 2021/12/4 21:28
    */
    @Service
    public class WxPayServiceImpl implements PayService {

    @Override
    public PayEnum getPayType() {
    return PayEnum.WX;
    }

    @Override
    public void pay(Object obj) {
    // wx支付逻辑
    System.out.println("使用了微信支付");
    }
    }

    /**
    * 支付宝支付处理类
    *
    * @author ZXP
    * @date 2021/12/4 21:29
    */
    @Service
    public class AliPayServiceImpl implements PayService {

    @Override
    public PayEnum getPayType() {
    return PayEnum.ALIPAY;
    }

    @Override
    public void pay(Object obj) {
    // 支付宝支付的逻辑
    System.out.println("使用了支付宝支付");
    }
    }
  4. 定义支付处理类工厂PayServiceFactory,管理所有PayService的实现类,该类实现了Spring提供的ApplicationContextAware接口,重写setApplicationContext(ApplicationContext applicationContext)方法,可以通过ApplicationContext获取所有PayService的实现类,然后注册到Map中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    /**
    * PayServiceFactory
    *
    * @author ZXP
    * @date 2021/12/4 21:31
    */
    @Component
    public final class PayServiceFactory implements ApplicationContextAware {

    private static final Map<PayEnum, PayService> SERVICES = new ConcurrentHashMap<>(16);

    /**
    * 通过支付类型获取具体的支付处理类
    *
    * @param payEnum
    * @return
    */
    public static PayService get(PayEnum payEnum) {
    return SERVICES.get(payEnum);
    }

    /**
    * 通过code获取支付处理类
    *
    * @param code
    * @return
    */
    public static PayService get(int code) {
    return get(PayEnum.getByCode(code));
    }

    /**
    * 注册PayService
    *
    * @param payService
    * @return
    */
    public static void register(PayService payService) {
    SERVICES.put(payService.getPayType(), payService);
    }

    /**
    * 初始化方法
    *
    * @param applicationContext
    * @throws BeansException
    */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    // 从容器中获取全部的支付处理类,注册到
    Map<String, PayService> payServices = applicationContext.getBeansOfType(PayService.class);
    for (PayService payService : payServices.values()) {
    // 注册到map中
    register(payService);
    }
    }
    }

使用演示

1
2
3
4
5
6
7
@Test
public void testPay() {
// 微信支付
PayServiceFactory.get(PayEnum.WX).pay(new Object());
// 支付宝支付
PayServiceFactory.get(PayEnum.ALIPAY).pay(new Object());
}

运行结果:

运行结果

总结

上述使用策略模式将不同支付类型的处理逻辑分发到不同的支付处理类中处理,可读性也较强,之后如果要增加新的支付方式,只需要添加一种枚举类型,新增加一个PayService的实现类即可,PayServiceFactory会自动将所有实现类注册到自己内部的Map中,从而使用时只需要通过支付类型到PayServiceFactory中获取支付处理类即可。

扩展

如若某些类型处理逻辑大致相同,只有某些小步骤不相同,此时可以引入模板方法模式加以处理,大致逻辑时在PayService和实现类之间增加一个抽象类,抽象类中重写相同的方法,某些特定步骤则下沉到具体实现类中处理。

扩展实现如下:Spring中使用模板方法模式

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=39o1a2zkjx8gg