温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Spring Boot策略模式怎么使用

发布时间:2021-12-18 11:21:31 来源:亿速云 阅读:301 作者:iii 栏目:互联网科技

这篇文章主要介绍“Spring Boot策略模式怎么使用”,在日常操作中,相信很多人在Spring Boot策略模式怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Spring Boot策略模式怎么使用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

未使用策略模式时的处理

以物联网为例大家可能不够熟悉,下面就以支付场景为例。比如在支付的过程中我们可能会选择微信支付、支付宝支付或银卡支付。同时,银行卡又分不同银行,这里统一为银行卡。

最简单直接的代码实现形式如下:

public void pay(String payType){
    if("alipay".equals(payType)){
        System.out.println("支付宝");
    }else if("wechatPay".equals(payType)){
        System.out.println("微信支付");
    } else if("bank".equals(payType)){
        System.out.println("银行卡支付");
    }
}

这样对照设计模式,通常不符合两个原则:单一职责原则和开闭原则。

我们会发现当前类(或方法)不处理了多个业务的功能,一旦任何一个支付方式的修改都可能会影响到其他的支付方式。同时,无法做到对扩展开放,对修改关闭。新增其他支付方式时同样要修改ifelse判断,影响到其他的业务逻辑。

而策略模式通常就是解决这种有很多ifelse处理逻辑,从而提高代码的可维护性、可扩展性和可读性。

策略模式的轮廓

在对上述代码进行改造之前,先来了解一下策略模式的基本组成。

策略模式(Strategy),定义了一组算法,将每个算法都封装起来,并且使它们之间可以互换。

策略模式通常有以下几部分组成:

  • Strategy策略类,用于定义所有支持算法的公共接口;

  • ConcreteStrategy具体策略类,封装了具体的算法或行为,继承于Strategy。

  • Context上下文,用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用;

  • StrategyFactory策略工厂类,用于创建策略类的具体实现;通常此部分可省略,看具体情况。比如后续实例中通过Spring的依赖注入机制实现了策略类的实例化。

用类图来表示(省略策略工厂类)如下图:

Spring Boot策略模式怎么使用

基于Spring的策略模式实现

目前在实践中通常都是基于Spring的特性来实现策略模式,这里就以此为例来进行讲解。

策略类定义

上面已经提到,策略类用于定义功能的接口,对于支付场景则可命名为PaymentService或PaymentStrategy。

public interface PaymentService {

    /**
     * 支付
     */
    PayResult pay(Order order);
}

同时提供该策略类的不同实现类:AlipayService、WeChatPayService、BankPayService。

@Service("alipay")
public class AlipayService implements PaymentService {
    @Override
    public PayResult pay(Order order) {
        System.out.println("Alipay");
        return null;
    }
}
@Service("wechatPay")
public class WeChatPayService implements PaymentService {
    @Override
    public PayResult pay(Order order) {
        System.out.println("WeChatPay");
        return null;
    }
}
@Service("bank")
public class BankPayService implements PaymentService {
    @Override
    public PayResult pay(Order order) {
        System.out.println("BankPay");
        return null;
    }
}

具体实现的实例化,可以通过一个PaymentFactory来进行构建存储,也可以直接利用@Autowired形式注入到Context的List或Map当中。

PaymentFactory的实现如下:

public class PaymentFactory {

    private static final Map<String, PaymentService> payStrategies = new HashMap<>();

    static {
        payStrategies.put("alipay", new AlipayService());
        payStrategies.put("wechatPay", new WeChatPayService());
        payStrategies.put("bank", new BankPayService());
    }

    public static PaymentService getPayment(String payType) {
        if (payType == null) {
            throw new IllegalArgumentException("pay type is empty.");
        }
        if (!payStrategies.containsKey(payType)) {
            throw new IllegalArgumentException("pay type not supported.");
        }
        return payStrategies.get(payType);
    }
}

通过static静态代码块来初始化对应的策略实现类,然后提供一个getPayment方法,根据支付类型来获取对应的服务。当然,通过static初始化的代码块是单例的无状态的,如果需要有状态的类则getPayment方法,每次都需要new一个新的对象。

public static PaymentService getPayment1(String payType) {
    if (payType == null) {
        throw new IllegalArgumentException("pay type is empty.");
    }
    if ("alipay".equals(payType)) {
        return new AlipayService();
    } else if ("wechatPay".equals(payType)) {
        return new WeChatPayService();
    } else if ("bank".equals(payType)) {
        return new BankPayService();
    }
    throw new IllegalArgumentException("pay type not supported.");
}
Context上下文

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

上面通过工厂的形式创建策略类的实现类,当然也可以直接通过@Autowired注入到Context上下文中。

@Component
public class PaymentStrategy {

    @Autowired
    private final Map<String, PaymentService> payStrategies = new HashMap<>();

    public PaymentService getPayment(String payType) {
        if (payType == null) {
            throw new IllegalArgumentException("pay type is empty.");
        }
        if (!payStrategies.containsKey(payType)) {
            throw new IllegalArgumentException("pay type not supported.");
        }
        return payStrategies.get(payType);
    }
}

上面通过@Autowired注解,将通过@Service实例化的PaymentService实现类,注入到map当中,其中key为实例化类的名称,value为具体的实例化类。

上面的getPayment代码与PaymentFactory中一致。当然,还可以在PaymentStrategy中封装一个pay方法,这样,客户端直接注入PaymentStrategy类调用pay方法即可。

public PayResult pay(String payType,Order order){
    PaymentService paymentService = this.getPayment(payType);
    return paymentService.pay(order);
}

改进方案

通过上面的代码基本上已经实现了策略模式,此时当新增加一个支付通道时,已经不用修改PaymentStrategy相关的代码,只用新增一个实现PaymentService接口的类即可。

但在接口定义这里,还是有优化空间的。比如,这里判断是通过Bean的名称来判断的,但某些情况下判断可能比较复杂或可能会同时执行多个Service。此时,就可以对PaymentService接口进行改进,新增一个检验是否支持该功能的判断方法。

public interface PaymentService {

    boolean isSupport(Order order);

    /**
     * 支付
     */
    PayResult pay(Order order);
}

由实现类来具体实现isSupport方法,判断自己支持哪些功能。

同时,上下文类也可以进一步利用Java8提供的Steam特性进行处理:

@Component
public class PaymentStrategy {

    /**
     * 此处用@Autowired将所有实例注入为List。
     */
    @Autowired
    private List<PaymentService> paymentServices;

    public void pay(Order order) {
        PaymentService paymentService = paymentServices.stream()
                .filter((service) -> service.isSupport(order))
                .findFirst()
                .orElse(null);

        if (paymentService != null) {
            paymentService.pay(order);
        } else {
            throw new IllegalArgumentException("pay type not supported.");
        }
    }
}

通过进一步改造,程序变得更加灵活了。

到此,关于“Spring Boot策略模式怎么使用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI