相信接触过Spring的同学,对于依赖注入并不陌生。

刚开始在听说这个名字的时候,一直不明白到底什么叫依赖注入,后来才发现,依赖注入一直都存在我们日常代码中,只是我们没有刻意的把它提出来,然后再取这样一个名字。

最开始我们在定义一个类的时候它往往会依赖于其他的类,比如拼写检查器依赖于字典:

作为工具类,我们一般是声明为静态工具类的:

public class SpellChecker {
private static final EnglishDic dictionary=new Lexicon();

//禁止实例化
private SpellChecker(){} public static boolean isValid(String word){} public static List<String> suggestions(String typo){}
}

或者将SpellChecker定义为单例的:

public class SpellChecker {
private final EnglishDic dictionary = ...; private SpellChecker(...) {}
public static INSTANCE = new SpellChecker(...); public boolean isValid(String word) { ... }
public List<String> suggestions(String typo) { ... }
}

可以看到我们是依赖于EnglishDic类的,假如这个时候项目已经完成并且发版,这个时候老板说有个德国的客户想要使用咱们库,希望咱们同时支持德语。这个时候,我们不得不修改代码将EnglishDic修改为GermanDic,然后再发一版。

后来随着业务扩展越来越大,需要支持各种语言,如果依然用这种方式存在的话,那么我们将维护几十个版本。这个时候,聪明的人就会想到,dictionary不在刚开始就定义好,而是作为可变属性,在用户使用的时候自己传递一个字典对象来,这样我们就只用维护一个版本即可。

此时我们有两个选择

一个是增加一个setter。(当然这是不可行的,因为你无法保证用户什么时候调用setter,而且比较笨拙)

其实我们可以看到上面的需求已经改变,因为后来的需求变为了每个用户希望拥有定制化的字典属性,所以我们抛弃静态工具类的设置,而使用依赖注入

// Dependency injection provides flexibility and testability
public class SpellChecker {
private final Lexicon dictionary; public SpellChecker(Lexicon dictionary) {
this.dictionary = Objects.requireNonNull(dictionary);
} public boolean isValid(String word) { ... }
public List<String> suggestions(String typo) { ... }
}

这样客户需要使用什么字典都由客户自己决定,而我们的代码也不需要维护多份。

依赖注入通俗的解释就是将类所依赖的对象作为参数让使用者在调用的时候注入

这样能够使代码更加灵活。

依赖注入什么时候用呢?

当一个类依赖于另外一个可变的类的时,可变的类应该使用注入的方式初始化

在实际情况中,一个类可能依赖很多个类的对象。这个时候可以结合使用builder方式构建。

或者:Spring了解一下。

《Effective Java》 读书笔记(五)使用依赖注入取代原本的资源依赖的更多相关文章

  1. 5. Effective Java 第三版——使用依赖注入取代硬连接资源

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  2. Effective Java 第三版——5. 使用依赖注入取代硬连接资源

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  3. Effective java读书笔记

    2015年进步很小,看的书也不是很多,感觉自己都要废了,2016是沉淀的一年,在这一年中要不断学习.看书,努力提升自己 计在16年要看12本书,主要涉及java基础.Spring研究.java并发.J ...

  4. Effective Java读书笔记完结啦

    Effective Java是一本经典的书, 很实用的Java进阶读物, 提供了各个方面的best practices. 最近终于做完了Effective Java的读书笔记, 发布出来与大家共享. ...

  5. Effective java 读书笔记(2)

    第四条:通过私有构造器强化不可实例化的能力 有时可能需要编写只包含静态方法和静态域的类,这样的工具类不希望被实例化,因为实例化对它来说没有意义. 然而,在缺少显式构造器的情况下,系统会自动提供一个缺省 ...

  6. Effective Java 读书笔记(一):使用静态工厂方法代替构造器

    这是Effective Java第2章提出的第一条建议: 考虑用静态工厂方法代替构造器 此处的静态工厂方法并不是设计模式,主要指static修饰的静态方法,关于static的说明可以参考之前的博文&l ...

  7. Effective Java 读书笔记(一):创建和销毁对象

    1 构造器 => 静态工厂方法 (1)优势 静态工厂方法有名字 静态工厂方法不必在每次被调用时都产生一个新的对象 静态工厂方法能返回原返回类型的任意子类型的对象 静态工厂方法根据调用时传入的不同 ...

  8. Effective Java读书笔记--创建和销毁对象

    1.优先考虑用静态工厂方法代替构造器2.遇到多个构造器参数时要考虑使用构建器Builder解决参数过多,不可变类型.私有构造方法,静态类的构造方法提供必要参数,剩下可选.new xxx.build() ...

  9. Effective Java 读书笔记(五):Lambda和Stream

    1 Lamdba优于匿名内部类 (1)DEMO1 匿名内部类:过时 Collections.sort(words, new Comparator<String>() { public in ...

随机推荐

  1. Oracle 的 rownum 问题

    对于 Oracle 的 rownum 问题,很多资料都说不支持>,>=,=,between...and,只能用以上符号(<.<=.!=),并非说用>,>=,=,be ...

  2. ng service(服务)

    ng service(服务) 创建服务命令:ng g service services/+服务名 使用服务的注意事项: 使用(services)服务需要在app.,module.ts(根模块)中引用并 ...

  3. MongoDB 学习笔记之 从数组中删除元素和指定数组位置

    从数组中删除元素: 从数组中删除单个元素: db.ArrayTest.updateOne({ "name" : "Bill"},{$pop: {"ad ...

  4. js时间查询补充

    先来看下JS中的日期操作: var myDate = new Date(); myDate.getYear(); //获取当前年份(2位) myDate.getFullYear(); //获取完整的年 ...

  5. 02-20 kd树(鸢尾花分类)

    [TOC] 更新.更全的<机器学习>的更新网站,更有python.go.数据结构与算法.爬虫.人工智能教学等着你:https://www.cnblogs.com/nickchen121/ ...

  6. restTemplate getForObject中map传参问题

    在使用restTemplate中getForObject的map传参形式时: 开始时我是这么调用的: RestTemplate rest = new RestTemplate(); Map<St ...

  7. GUI tkinter (Entry) 输入框篇

    """1.其他函数不常用,这里只说get函数,get函数使用的时候不需要任何参数,它的返回值就是该输入框的内容.""" from tkint ...

  8. Spring Boot 2.2 正式发布,大幅性能提升 + Java 13 支持

    之前 Spring Boot 2.2没能按时发布,是由于 Spring Framework 5.2 的发布受阻而推迟.这次随着 Spring Framework 5.2.0 成功发布之后,Spring ...

  9. go 学习笔记之解读什么是defer延迟函数

    Go 语言中有个 defer 关键字,常用于实现延迟函数来保证关键代码的最终执行,常言道: "未雨绸缪方可有备无患". 延迟函数就是这么一种机制,无论程序是正常返回还是异常报错,只 ...

  10. lcx 内网转发

    把放置到已经控制的内网主机 执行 内网主机输入命令lcx.exe -slave 外网ip 外网端口 内网ip 内网端口lcx.exe -slave 30.1.85.55 2222 127.0.0.1 ...