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. RF(IF 判断)

    1.关键字 Run Keyword If,格式如下: ELSE   必须大写 ELSE   前面需要加 "..." 表示缩进 Run Keyword If a == b log T ...

  2. libevent(二)尾队列 && 最小堆

    本文主要研究libevent中用来存储事件的两个结构体. 尾队列 具体定义位于queue.h中. #define TAILQ_HEAD(name, type) \ struct name { \ st ...

  3. Go中的数组切片的使用总结

    代码示例 package main import "fmt" func main(){ fmt.Println("Hello, world") // 定义数组的 ...

  4. leetcode_雇佣 K 名工人的最低成本(优先级队列,堆排序)

    题干: 有 N 名工人. 第 i 名工人的工作质量为 quality[i] ,其最低期望工资为 wage[i] . 现在我们想雇佣 K 名工人组成一个工资组.在雇佣 一组 K 名工人时,我们必须按照下 ...

  5. 【Scala】用实例弄清楚scala几种函数的定义和特点

    文章目录 作为参数的函数 匿名函数 柯里化函数(currying) 闭包函数 作为参数的函数 scala> val a1 = Array(1,2,3,4) //这是一个数组 a1: Array[ ...

  6. ocaml 和coq 安装

    安装opam 参考官网安装步骤即可,比如对于centos系统,以root用户执行如下指令 cd /etc/yum.repos.d/ wget http://download.opensuse.org/ ...

  7. ApplicationInsights迁移国内躺的坑

    由于之前有段时间访问国际版的Application Insights实在是慢,而且又不是每个人都有梯子,然后国内版大概在去年(2019)六七月左右已经上线,想着也有一段时日了,要么就迁了吧. 然后实际 ...

  8. 管理环境一:venv

    初衷: 在工作的时候,我们会有很多个项目,每个项目使用的库的版本不一样,导致我们切换项目的时候会很麻烦. 比如:我有两个django项目,项目一使用的版本是 django 1.7 , 项目二使用的版本 ...

  9. mysqldump 参数--single-transaction

    其实很简单,single-transaction可以让mysqldump 的时候不锁表.但是他有3个前提 innodb的引擎 不能在执行的同时,有其他alter table ,drop table,r ...

  10. IDEA将Maven项目中指定文件夹下的xml等文件编译进classes

    eclipse下面创建的Maven项目,使用mybatis.eclipse里面能正常启动,在idea中一直卡在maybatis 加载位置. 1.首先是不报错也没反应.这个时候需要我们重写SqlSess ...