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("=======支付类型错误========"); } } }
完美!