javaeye上看到有帖子,置疑spring和依赖注入的价值,回复内容整理如下:

依赖注入对设计有利,而spring则促进了依赖注入的使用。

如果业务处理类,它所使用的倚赖,都是依靠在这个类内部实现或者查找,那么必然使得正常的业务逻辑和获取依赖的方法混在一起。

我取个最简单的场景,某个注册的工作类,它需要获取当前"容许的用户名的最大长度",这个依赖非常简单吧?基本每个注册类都有这个限制,我们现在 把场景考虑的全面一点,对于复杂一点的系统,这个最大长度的限制可能来源很多,比如配制文件,数据库,可能类工作在前台比如web而配制在后台,可能需要 和第三放系统一起工作而需要到第三方系统中获取而对方只提供web service...

这么一个简单的依赖,“用户名的最大长度”,如果用依赖注入,只要一个简单的setUsernameMaxLength()方法就可以搞定。考虑 上面那么多种可能都出现,最恶劣的情况是要求一个系统可以同时支持然后通过配制方式进行,这对于将一个产品卖给n家客户的公司来说是最正常不过的要求。

那么我们来看一个很有"spring"风格的采用依赖注入的设计,通常都将会是这样:

注册工作类:
public void RegisterWork {
public void setUsernameMaxLengthProvider(UsernameMaxLengthProvider provider) {
int maxLength = provider.getUsernameMaxLength(); //简单获取结果,不管provider细节
}
....
}
“用户名的最大长度”的提供者接口
public interfacd UsernameMaxLengthProvider {
public int getUsernameMaxLength();
}
“用户名的最大长度”的提供者则可以有以下实现,都只负责读取数据,不关心数据被谁使用,怎么使用:
1.直接提供,可以用spring 构造函数方式注入usernameMaxLength值,也可以junit测试时直接new DirectdProvide对象
public class DirectdProvider implements UsernameMaxLengthProvider  {
private int usernameMaxLength = 10;
public int getUsernameMaxLength() {
return UsernameMaxLength;
}
public DirectdProvider (int usernameMaxLength) {
this.usernameMaxLength = usernameMaxLength;
}
}
2.读本地配制文件
public class LocalConfigFileProvider implements UsernameMaxLengthProvider  {
public void read(File configFile) {
usernameMaxLength = ....
}
}
3.类似的从数据库读取 DatabaseProvide
4.类似的web service从第三方读取 WebServiceProvider
5.其他的可能扩展的方式

开发时逻辑清晰,代码可读性超强,基本看类名和函数名搞定。测试时,轻松测试RegisterWork,testcase中只要 worker.setUsernameMaxLengthProvider(new DirectdProvider(20))就搞定。而针对UsernameMaxLengthProvider的几个实现类,更是轻松使用junit,每 个都覆盖一遍。

呵呵,现在我们可以砍刀,最简单的一个int型的“用户名的最大长度”,都可能遭遇如此复杂的场景。如果不用倚赖注入,而是选择在RegisterWork中自己搞定“用户名的最大长度”的获取,那么可能要遇到以下问题:
1. RegisterWork极其复杂,可以想像类似的依赖肯定还有其他
2. 获取“用户名的最大长度”的方式和注册的业务处理逻辑完全没有直接联系,对注册过程来说它只关注结果,“用户名的最大长度”是10还是20,而不是到底读本地文件还是读数据库。喧宾夺主了,次要逻辑干扰了主要逻辑
3. 难于测试。获取“用户名的最大长度”的方式的这些代码,被藏在RegisterWork类中,而且很有可能是private方法不对外暴露(如果不依赖注入还需要暴露吗?暴露给谁呢),怎么用mock测试?怎么能保证以上几种的实现都覆盖到?
4. 难于扩展。就算上面都搞定了,某一天突然来了一个变态需求,要求用ldap从另一个地方取配置呢?难道再把ldap请求的那一大片代码也写到RegisterWork里面?
5. 更难于被第三方扩展。运气好,上面这个ldap取配制的变态需求客户开始没有要求。顺利开发完成测试通过然后准备上线,最后一晚了客户才发现,"哦,给忘 了,你们想办法给加上,快,快,明天一早就要上线运行了...你们写死在代码里面了?那只能你们修改了原代码了"。吐血了吧,先骂一顿,可是活还的干啊, 咬牙切齿的把新的实现代码加上了,还得编译打包更新重启...如果是spring多好,单独写一个LdapProvider类,测试(这个测试比杂在 RegisterWork里面测试简单的多)通过后单独提供这个class仍classpath下,修改spring的配制将原来的 ***Provider替换掉,轻松搞定,甚至可以把这活仍给客户的开发人员,告诉他们怎么替换就可以了,管你ladp还是其他,谁让你们需求不明确,自 己扩展去。
6. 容易出错。刚吐血完成上面的变态需求,更新完毕,一会客户电话来了,“...怎么...不正常了?”。又吐血几升地检查,终于找出来了,原来是刚才写 ladp访问的代码时不小心改错了RegisterWork的一个地方,谁让RegisterWork类有几十上百个方法好几千行呢,一时急,又没有测试 到......可是客户不会理解的。

上述的场景,spring + 依赖注入的设计方式,优点很明显吧。

再考虑一下维护和二次开发的问题,上面的spring + 依赖注入的代码,好看易懂,方便扩展,维护起来轻松。如果是那么堆在RegisterWork里面,在那个大堆中代码要找出这些代码并读懂,估计不是件轻松的事情。

代码维护是需要成本的,写出易于维护的代码,是一个优秀程序员的基本素养,至少,不能让下一个接手的人骂娘吧?

Spring和依赖注入的价值的更多相关文章

  1. (spring-第3回【IoC基础篇】)spring的依赖注入-属性、构造函数、工厂方法等的注入(基于XML)

    Spring要把xml配置中bean的属性实例化为具体的bean,"依赖注入"是关卡.所谓的"依赖注入",就是把应用程序对bean的属性依赖都注入到spring ...

  2. Spring的依赖注入(DI)三种方式

    Spring依赖注入(DI)的三种方式,分别为: 1.  接口注入 2.  Setter方法注入 3.  构造方法注入 下面介绍一下这三种依赖注入在Spring中是怎么样实现的. 首先我们需要以下几个 ...

  3. spring的依赖注入的最常见的两种方法

    package com.lsz.spring.action; public class User { /** * set注入 */ private String username; public vo ...

  4. 一步一步深入spring(3)--spring的依赖注入方式

    对于spring配置一个bean时,如果需要给该bean提供一些初始化参数,则需要通过依赖注入方式,所谓的依赖注入就是通过spring将bean所需要的一些参数传递到bean实例对象的过程,sprin ...

  5. spring的依赖注入是什么意思

    最近学习spring框架,对依赖注入有些模糊,遂上网翻阅资料,做了下列总结,原博客为CSDN 南夏的 spring的依赖注入是什么意思,侵删! Spring 能有效地组织J2EE应用各层的对象.不管是 ...

  6. SpringBoot系列: 理解 Spring 的依赖注入(一)

    ==============================Spring 的依赖注入==============================对于 Spring 程序, Spring 框架为我们提供 ...

  7. Spring.NET依赖注入框架学习--实例化容器常用方法

    Spring.NET依赖注入框架学习---实例化容器常用方法 本篇学习实例化Spring.NET容器的俩种方式 1.通过XmlObjectFactory创建一个Spring.NET容器 IResour ...

  8. Spring.NET依赖注入框架学习--简单对象注入

    Spring.NET依赖注入框架学习--简单对象注入 在前面的俩篇中讲解了依赖注入的概念以及Spring.NET框架的核心模块介绍,今天就要看看怎么来使用Spring.NET实现一个简单的对象注入 常 ...

  9. Spring.NET依赖注入框架学习--简介

    Spring.NET依赖注入框架学习--Spring.NET简介 概述 Spring.NET是一个应用程序框架,其目的是协助开发人员创建企业级的.NET应用程序.它提供了很多方面的功能,比如依赖注入. ...

随机推荐

  1. 「6月雅礼集训 2017 Day4」暴力大神hxx

    [题目大意] 给出一个n重循环,每重循环有范围$[l, r]$,其中$l$,$r$可能是之前的变量,也可能是常数.求循环最底层被执行了多少次. 其中,保证每个循环的$l$,$r$最多有一个是之前的变量 ...

  2. 20155335俞昆《java程序设计》第十周总结

    学号 2016-2017-2 <Java程序设计>第十周学习总结 ## 事实上网络编程,我们可以简单的理解为两台计算机相互通讯数据而已,对于程序员而言,掌握一种编程接口并使用一种编程模型相 ...

  3. Hibernate数据连接不能正常释放的原因,以及在监听中获取apolicationContext上下文

    Hibernate数据库连接不能正常释放: https://blog.csdn.net/u011644423/article/details/44267301 监听中获取applicationCont ...

  4. Spring与MyBatis的整合(山东数漫江湖)

    首先看一下项目结构图: 具体步骤如下: 1.建立JDBC属性文件 jdbc.properties (文件编码修改为 utf-8 ) driver=com.mysql.jdbc.Driver url=j ...

  5. Desert King(POJ2728+最优比率生成树+二分)

    题目链接:http://poj.org/problem?id=2728 题目: 题意:求一颗生成树,使得费用与距离的比值最小,其中距离等于两点之间的平面欧拉距离,费用为z坐标之差. 思路: 由上图我们 ...

  6. Python 关于时间和日期函数使用 -- (转)

    python中关于时间和日期函数有time和datatime   1.获取当前时间的两种方法: import datetime,time now = time.strftime("%Y-%m ...

  7. hdu 2680 Choose the best route (dijkstra算法 最短路问题)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2680 Choose the best route Time Limit: 2000/1000 MS ( ...

  8. Android中的异常情况

    1.setText()方法中,如果参数是int类型,Android会把它当做是一个id查找,报以下异常,因此解决办法就是将参数转化为String类型 如:setText(num) è setText( ...

  9. 排序中topK那点事(转)

    问题描述:有 N (N>1000000)个数,求出其中的前K个最小的数(又被称作topK问题). 这类问题似乎是备受面试官的青睐,相信面试过互联网公司的同学都会遇到这来问题.下面由浅入深,分析一 ...

  10. 异步网络模块之aiohttp的使用(一)

    异步网络模块之aiohttp的使用(一) 平时我们也许用的更多的是requests模块,或者是requests_hml模块,但是他们都属于阻塞类型的不支持异步,速度很难提高,于是后来出现了异步的gre ...