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")思想的更多相关文章

  1. 通过ApplicationContext.getBean(beanName)动态加载数据。

    一,前台数据 $.ajax({ url: '/intra/coe/order/ploadTable.htm', type: 'POST', dataType: 'json', data: {keyId ...

  2. spring项目获取ApplicationContext(能手动从Spring获取所需要的bean)

    最流行的方法就是  实现ApplicationContextAware接口 @Component public class SpringContextUtil implements Applicati ...

  3. spring BeanFactory及ApplicationContext中Bean的生命周期

    spring bean 的生命周期 spring BeanFactory及ApplicationContext在读取配置文件后.实例化bean前后.设置bean的属性前后这些点都可以通过实现接口添加我 ...

  4. spring中获取applicationContext

    常用的5种获取spring 中bean的方式总结: 方法一:在初始化时保存ApplicationContext对象代码:ApplicationContext ac = new FileSystemXm ...

  5. 死磕Spring之IoC篇 - Spring 应用上下文 ApplicationContext

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...

  6. 一) Spring 介绍、IOC控制反转思想与DI依赖注入

    一.spring介绍1.IOC反转控制思想(Inversion of Control)与DI依赖注入(Dependency Injection)2.AOP面向切面的编程思想与动态代理3.作用:项目的粘 ...

  7. springbank 开发日志 一次因为多线程问题导致的applicationContext.getBean()阻塞

    几天前遇到的这个问题.由于交易是配置的,不同的交易是同一个类的不同实例,所以不可能提前将其以@autowired类似的方式注入到需要的类中 <op:transaction id="Re ...

  8. Spring +quartz获取ApplicationContext上下文

    job存在数据库中,能够进行动态的增增删改查,近期遇到了怎样获取ApplicationContext上下文的问题.解决的方法例如以下 applicationContext-quartz.xml < ...

  9. Spring注解--实现applicationContext.xml效果

    随着越来越多地使用Springboot敏捷开发,更多地使用注解配置Spring,而不是Spring的applicationContext.xml文件. Configuration注解: Spring解 ...

随机推荐

  1. .Net Core中使用Dapper构建泛型仓储

    前言:Dapper是.NET的简单对象映射器,在速度方面拥有ORM之王的称号,与使用原始ADO.NET读取数据一样快.ORM是对象关系映射器,它负责数据库和编程语言之间的映射. 仓储主要是用来解耦业务 ...

  2. unittest(封装用例)

    from selenium import webdriver from time import sleep import unittest #导入unittest库 import HTMLTestRu ...

  3. 一只简单的网络爬虫(基于linux C/C++)————利用正则表达式解析页面

    我们向一个HTTP的服务器发送HTTP的请求后,服务器会返回可能一个HTML页面(当然也可以是其他的资源),我们可以利用返回的HTML页面,在其中寻找其他的Url,例如我们可以这样在浏览器上查看一下H ...

  4. Java采用反射技术创建对象后对目标类的成员变量和成员方法进行访问

    实现: package com.ljy; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * * @Class ...

  5. Python解决钻石小偷问题

    题目如下: A:我没有偷钻石. B:D就是罪犯. C:B是盗窃这块钻石的罪犯. D:B有意诬陷我. 假定只有一个人说的是真话,编程序判断谁偷走了钻石. 答案是:说真话的是D,罪犯是A,逻辑思路可以百度 ...

  6. SpringBoot返回JSON日期格式问题

    SpringBoot中默认返回的日期格式类似于这样: "birth": 1537407384500 或者是这样: "createTime": "201 ...

  7. Python爬虫丨大众点评数据爬虫教程(2)

    大众点评数据爬虫获取教程 --- [SVG映射版本] 前言: 大众点评是一款非常受大众喜爱的一个第三方的美食相关的点评网站.从网站内可以推荐吃喝玩乐优惠信息,提供美食餐厅.酒店旅游.电影票.家居装修. ...

  8. Linux开机自启动脚本的总结

    一.在/etc/rc.local中添加 如果不想将脚本粘来粘去,或创建链接什么的, 则: step1. 先修改好脚本,使其所有模块都能在任意目录启动时正常执行; step2. 再在/etc/rc.lo ...

  9. Excel心得

    智能表.数据透视表.分类汇总表是Excel最值得学的技能. 通过插入表,或者快捷键Ctrl+T/Ctrl+L,可以将区域转换为智能表,保证了字段的公式的统一,而且版式自动化处理,一深一浅.Ctrl+Q ...

  10. 自动化测试工具-Selenium IDE 教程一

    引言:这里介绍的是谷歌浏览种的插件,安装教程这里不再描述,网上有很多, 使用教程不是特别多,所以特地花时间整理此篇内容: 一:打开插件,欢迎界面 启动IDE后,将显示一个欢迎对话框. 如果这是您第一次 ...