Spring boot 运用策略模式实现避免多次使用if的操作代码

 更新时间:2022年08月24日 14:23:42   作者:我赢了算我输  
这篇文章主要介绍了Spring boot 运用策略模式实现,避免多次使用if,使用策略模式后,新加一种支付策略时,只需要在策略枚举中添加新加的策略信息,外加一个策略类即可,而不再需要添加新的if判断,需要的朋友可以参考下

前言

这里就不详细去介绍策略模式是怎么样的了,想了解的可以点击下面的链接

策略模式介绍的链接:策略模式的介绍

这里列出策略模式的好处

场景:某网页有个支付,其中包含了微信、支付宝等方式的支付方式 ,后续明确还会进行兼容其他的支付方式

用策略模式的好处:

  • 避免多次使用if判断具体是用哪种支付策略进行操作。
  • 因为每种策略(微信支付、支付宝支付)的内容都比较复杂。策略模式能将每种策略分离出来,方面后续维护管理

下面我们将使用Spring boot 运用策略模式,实现上面的需求

环境配置

  • JDK8
  • Spring boot 2.3.7.RELEASE
  • 整合了spring-boot-starter-web

实现目标

使用策略模式后,新加一种支付策略时,只需要在策略枚举中添加新加的策略信息,外加一个策略类即可,而不再需要添加新的if判断。

准备策略接口和具体实现策略类

支付策略接口

/**
 * 支付策略
 */
public interface PayStrategy {

    /**
     * 支付(参数就没具体写了,可以定义成每个支付必须要有的参数)
     * @return
     */
     boolean pay();
}

微信支付策略类

/**
 * 第三方——微信支付(这里注意我修改了Bean的默认命名)
 */
@Component("wechatPayStrategy")
public class WeChatPayStrategyImpl implements PayStrategy{

    /**
     * 支付
     * @return
     */
    @Override
    public boolean pay() {

        //进行微信的支付逻辑
        System.out.println("正在进行微信的支付逻辑");

        return true;
    }
}

支付宝支付策略类

/**
 * 支付宝第三方支付(这里注意我修改了Bean的默认命名)
 */
@Component("alipayStrategy")
public class AliPayStrategyImpl implements PayStrategy {

    /**
     * 支付宝支付
     * @return
     */
    @Override
    public boolean pay() {

        //进行支付宝支付逻辑
        System.out.println("进行支付宝支付逻辑");
        return true;
    }
}

上述已将各自的策略的处理类进行了分离,接下来时使用支付策略工厂类和支付策略上下文将各自的策略类联系起来

准备支付策略上下文Context和支付策略工厂类

支付策略工厂类

package com.example.springboot_strategy.strategy.factory;

import com.example.springboot_strategy.enums.PayStrategyEnum;
import com.example.springboot_strategy.strategy.PayStrategy;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.swing.plaf.synth.SynthTextAreaUI;
import java.util.Map;

/**
 * 支付策略工厂类
 */
@Component
public class PayStrategyFactory {

    /**
     * 通过Spring容器的方式注入
     */
    @Resource
    private Map<String, PayStrategy> payStrategyMap;

    /**
     * 获取对应支付策略类
     * @param payStrategyEnum 支付策略枚举
     */
    public PayStrategy getPayStrategy(PayStrategyEnum payStrategyEnum){

        if(!payStrategyMap.containsKey(payStrategyEnum.getClassName())){
            System.out.println("没有对应的支付策略,无法进行支付");
            return null;
        }

        return payStrategyMap.get(payStrategyEnum.getClassName());
    }
}

这里工厂类的逻辑是利用了Spring容器的处理方式,如果有多种类同时实现了某个接口,那么可以使用Map集合接收,Map对应的泛型,String是Bean名称,PayStrategy是每个具体实现类,这样我们就可以使用Bean类型去指定具体的策略类了,然后建立一个支付策略枚举去管理这些Bean名称。同时,也可以将Bean名称与客户端定义的类型进行关联。

支付策略枚举类

/**
 * 支付策略类型
 */
public enum PayStrategyEnum {
    WECHAT_PAY("wechat","wechatPayStrategy","微信支付"),
    ALIPAY("alipay","alipayStrategy","支付宝支付")
    ;

    /**
     * 支付策略code
     */
    private String code;

    /**
     * bean名称
     */
    private String className;

    /**
     * 信息
     */
    private String info;

    PayStrategyEnum(String code,String className,String info){
        this.code=code;
        this.className=className;
        this.info=info;
    }


    public String getCode() {
        return code;
    }

    public String getClassName() {
        return className;
    }

    public String getInfo() {
        return info;
    }
}

上面枚举类中code代表的是客户端定义的类型(例如我从前端接收到的支付type,这个type可以是这个code),className顾名思义,指的是每种策略的bean名称,info是代表每种策略的内容

支付策略上下文

/**
 * 支付策略上下文
 */
@Component
public class PayStrategyContext {
    
    @Autowired
    private PayStrategyFactory payStrategyFactory;

    /**
     * 支付执行
     * @param payDTO 支付参数
     * @return
     */
    public boolean payHandle(PayDTO payDTO){
       
        //将某属性的值转换成具体的枚举。这里是根据payDTO的type字段对应枚举的code进行转换
        Optional<PayStrategyEnum> payStrategyEnumOptional = Arrays.stream(PayStrategyEnum.class.getEnumConstants())
                .filter((e) -> e.getCode().equals(payDTO.getType())).findAny();

        if(!payStrategyEnumOptional.isPresent()){
            System.out.println("匹配不到具体支付策略");
            return false;
        }
        PayStrategyEnum payStrategyEnum = payStrategyEnumOptional.get();

        PayStrategy payStrategy = payStrategyFactory.getPayStrategy(payStrategyEnum);

        //进行payDto参数的处理.....

        boolean pay = payStrategy.pay();

        //支付后的记录处理..


        return true;
        
    }
}

pageDto类

/**
 * 支付DTO
 */
public class PayDTO {

    /**
     * 支付类型
     */
    private String type;


    /**
     * 支付金额
     */
    private BigDecimal payMoney;
    
    /**
     * ...........
     */


    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public BigDecimal getPayMoney() {
        return payMoney;
    }

    public void setPayMoney(BigDecimal payMoney) {
        this.payMoney = payMoney;
    }

}

这个策略上下文,则是选择策略的入口,这里会进行参数的处理,将这里我就将pageDTO类中的type字符串转换成对应的枚举类。
到这里使用策略模式的编写算是完成了,下面进行编写客户端的代码

客户端代码

支付控制器

@RestController
@RequestMapping("pay")
public class PayController {

    @Autowired
    private PayStrategyContext payStrategyContext;

    @PostMapping
    public boolean pay(@RequestBody PayDTO payDTO){
    
        //这里因为懒。。就没有加上Service层了,直接在控制器处理
        return payStrategyContext.payHandle(payDTO);
    }
}

效果

新需求

后续新增一个银联的支付方式,我们只需要添加银联的支付策略类和添加银联的支付枚举即可实现

添加银联的支付策略类

/**
 * 银联支付(这里注意我修改了Bean的默认命名)
 */
@Component("unionPayStrategy")
public class UnionPayStrategyImp implements PayStrategy {


    /**
     * 银联支付
     * @return
     */
    @Override
    public boolean pay() {

        //进行银联的支付

        System.out.println("进行银联的支付逻辑");
        return true;
    }

}
复制代码

在枚举类中添加银联的支付枚举

/**
 * 支付策略类型
 */
public enum PayStrategyEnum {
    WECHAT_PAY("wechat","wechatPayStrategy","微信支付"),
    ALIPAY("alipay","alipayStrategy","支付宝支付"),
    UNION_PAY("unionpay","unionPayStrategy","银联支付")
    ;

    /**
     * 支付策略code
     */
    private String code;

    /**
     * bean名称
     */
    private String className;

    /**
     * 信息
     */
    private String info;

    PayStrategyEnum(String code,String className,String info){
        this.code=code;
        this.className=className;
        this.info=info;
    }


    public String getCode() {
        return code;
    }

    public String getClassName() {
        return className;
    }

    public String getInfo() {
        return info;
    }


}

实现效果

以上是我使用Spring boot 运用策略模式实现的效果,如果有误人子弟的地方,望在评论区指出。

到此这篇关于Spring boot 运用策略模式实现,避免多次使用if的文章就介绍到这了,更多相关Spring boot 策略模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springBoot加入thymeleaf模板的方式

    springBoot加入thymeleaf模板的方式

    这篇文章主要介绍了springBoot加入thymeleaf模板的方式,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • Java中关键字synchronized的使用方法详解

    Java中关键字synchronized的使用方法详解

    synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块,下面这篇文章主要给大家介绍了关于Java中synchronized使用的相关资料,需要的朋友可以参考下
    2021-08-08
  • SpringBoot+Querydsl 框架实现复杂查询解析

    SpringBoot+Querydsl 框架实现复杂查询解析

    本篇主要将介绍的是利用spring query dsl框架实现的服务端查询解析和实现介绍,对SpringBoot Querydsl 查询操作感兴趣的朋友一起看看吧
    2022-05-05
  • springboot整合spring-retry的实现示例

    springboot整合spring-retry的实现示例

    本文将结合实例代码,介绍springboot整合spring-retry的实现示例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • java定义受限制的类型参数操作

    java定义受限制的类型参数操作

    这篇文章主要介绍了java定义受限制的类型参数操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • java中javamail收发邮件实现方法

    java中javamail收发邮件实现方法

    这篇文章主要为大家详细介绍了java中javamail收发邮件实现方法,实例分析了javamail的使用方法与相关注意事项,非常具有实用价值,感兴趣的小伙伴们可以参考一下
    2016-02-02
  • 使用IDEA创建SpringBoot项目的方法步骤

    使用IDEA创建SpringBoot项目的方法步骤

    这篇文章主要介绍了使用IDEA创建SpringBoot项目的方法步骤,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05
  • 详解java装饰模式(Decorator Pattern)

    详解java装饰模式(Decorator Pattern)

    这篇文章主要为大家详细介绍了java装饰模式Decorator Pattern,这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装,对装饰器模式感兴趣的小伙伴们可以参考一下
    2016-04-04
  • 如何解决java中遇到的for input string:

    如何解决java中遇到的for input string: "" 报错问题

    在本篇文章里小编给大家整理的是一篇关于如何解决java中遇到的(for input string: "")报错内容,需要的朋友们可以学习下。
    2020-02-02
  • Java binarysearch方法原理详解

    Java binarysearch方法原理详解

    这篇文章主要介绍了Java binarysearch方法原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01

最新评论