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

大道之行,天下为公。这篇文章主要讲述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设计模式之applicationContext.getBean(" beanName" )思想】
spring设计模式之applicationContext.getBean("beanName")思想

文章图片

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

文章图片

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

文章图片

  结论:看到最后,你会发现,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("=======支付类型错误========"); } }}

完美!

    推荐阅读