相信接触过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了解一下。