spring设计模式之applicationContext.getBean("beanName")思想

Posted 姿势帝

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring设计模式之applicationContext.getBean("beanName")思想相关的知识,希望对你有一定的参考价值。

1.背景

在实际开发中我们会经常遇到不同的业务类型对应不同的业务处理,而这个业务类型又是经常变动的;

比如说,我们在做支付业务的时候,可能刚开始需要实现支付宝支付和微信支付,那么代码逻辑可能如下

/**
     * 支付选择简易逻辑
     *
     * @param payType payType zfb-支付宝支付,wx-微信支付
     * @param money   需要支付的钱
     */
    public void pay(String payType, Double money) {
        if ("zfb".equals(payType)) {
            System.out.println("=======执行支付宝支付========");
        } else if ("wx".equals(payType)) {
            System.out.println("=======执行支微信支付========");
        } else {
            System.out.println("=======支付类型错误========");
        }
    }

咋一看,这样写也没有什么问题,但是如果因业务需要我们需要增加一个京东支付,那么我们又要else if ().....

如果哪一天我们又要增加一个云闪付支付,那么我们又要else if ().....

如果哪一天我们又要.....................

这样的话,我们这个类会随着这支付类型的变动不断慢慢的扩展和修改....

在修改的过程中甚至将原来的弄错......

最后总结这样的代码违反了开闭原则,好的代码设计思想应该是对修改关闭,对扩展开放;

那么应该如何写呢?

大家可想想象一下,spring的getBean是怎么实现的,

applicationContext.getBean("beanName");

spring在设计的时候并不知道我们后来会写什么bean,它的内部不可能是通过名称 if else 来获取实例对象的,

分析到这里大家有没有感觉到,这里的业务逻辑与我们的支付选择逻辑是相同的,

既然这样,我们是不是可以看一看spring的getBean到是这样实现,如果能大体看懂,是不是我们也可以参照他的思想编写我们的支付逻辑.

2.spring的getBean源码分析

源码跟踪

 

 

 结论:看到最后,你会发现,spring的实例对象 是根据名称,以key,value的方式放在map中的;

那么,我们的支付逻辑是不是也可以根据支付类型以key-value的方式存放;这样就不会再使用if else.

3.支付业务逻辑实现

1.订单实现类

  主要逻辑,

a.在sping启动的时候,通过构造方法或去支付接口的所有实例

b.遍历实例,将实例以key-value的方式放入map

c.在具体支付的时候,通过支付类型从map中获取支付的具体实例,进行支付

package com.example.demo.service.impl;

import com.example.demo.service.IOrderService;
import com.example.demo.service.IPayService;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Copyright (C) XXXXXXXX
 * @Author: 姿势帝
 * @Date: 2020-05-29 9:56
 * @Description:
 */
@Service
public class OrderServiceImpl implements IOrderService {
    /**
     * 存放支付类型的实例
     */
    private Map<String, IPayService> mapPay = new HashMap<>();
    /**
     * 构造方法
     * spring在实例化的时候会将所有的IPayServcie的实例放入list,在通过遍历放入map
     *
     * @param list
     */
    public OrderServiceImpl(List<IPayService> list) {
        for (IPayService iPayService : list) {
            mapPay.put(iPayService.getPayType(), iPayService);
        }
    }
    /**
     * @param payType zfb-支付宝支付,wx-微信支付,ysf-云闪付
     * @param money
     * @return
     */
    @Override
    public Object pay(String payType, Double money) {
        IPayService payService = mapPay.get(payType);
        if (payService == null) {
            System.out.println("没有对应的支付方式-->" + payType);
            return null;
        }
        payService.doPay(money);
        return null;
    }
}

支付接口

package com.example.demo.service;

/**
 * @Copyright (C) XXXXXXXX
 * @Author: 姿势帝
 * @Date: 2020-05-29 9:59
 * @Description:
 */
public interface IPayService {
    /**
     * 获取支付类型
     * @return
     */
    String getPayType();

    /**
     * 具体支付
     * @param money
     * @return
     */
    Object doPay(Double money);
}

2.支付宝实现类

package com.example.demo.service.impl;

import com.example.demo.service.IPayService;
import org.springframework.stereotype.Service;

/**
 * @Copyright (C) XXXXXXXX
 * @Author: 姿势帝
 * @Date: 2020-05-29 10:01
 * @Description:
 */
@Service
public class PayAliPayServiceImpl implements IPayService {
    @Override
    public String getPayType() {
        return "zfb";
    }

    @Override
    public Object doPay(Double money) {
        System.out.println("======执行支付宝支付=======money="+money);
        return null;
    }
}

微信实现类

package com.example.demo.service.impl;

import com.example.demo.service.IPayService;
import org.springframework.stereotype.Service;

/**
 * @Copyright (C) XXXXXXXX
 * @Author: 姿势帝
 * @Date: 2020-05-29 10:01
 * @Description:
 */
@Service
public class PayWechatServiceImpl implements IPayService {
    @Override
    public String getPayType() {
        return "wx";
    }

    @Override
    public Object doPay(Double money) {
        System.out.println("======执行微信支付=======money="+money);
        return null;
    }
}

....如果以后有京东,云闪付....等只需要写一个实现类即可,其他代码不需要做任何修改

3.测试

package com.example.demo;

import com.example.demo.service.IOrderService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;

@SpringBootTest
class DemoApplicationTests {
    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private IOrderService orderService;

    /**
     * 测试支付
     * payType zfb-支付宝支付,wx-微信支付,其他支付....
     */
    @Test
    void testPay() {
        orderService.pay("zfb", 12.89);
    }

    /**
     * 获取bean的方法
     */
    @Test
    public void testBean() {
        applicationContext.getBean("beanName");
    }


    /**
     * 支付选择简易逻辑
     *
     * @param payType payType zfb-支付宝支付,wx-微信支付,其他支付....
     * @param money   需要支付的钱
     */
    public void pay(String payType, Double money) {
        if ("zfb".equals(payType)) {
            System.out.println("=======执行支付宝支付========");
        } else if ("wx".equals(payType)) {
            System.out.println("=======执行支微信支付========");
        } else {
            System.out.println("=======支付类型错误========");
        }
    }

}

完美!

以上是关于spring设计模式之applicationContext.getBean("beanName")思想的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot中常用的三个注解

spring_03ApplicationContext三种经常用到的实现

Springset注入(掌握)

解决spring boot中普通类中使用service为null 的方法

websocket无法注入问题解决方案

Spring 设计模式之责任链模式