05. 依赖注入优于硬连接资源
依赖注入优于硬连接资源
假设需要实现一个用于拼写检查的工具类,这个类里面依赖一个工具字典。有两种实现方法如下:
- 设计为静态工具类
// Inappropriate use of static utility - inflexible & untestable!
public class SpellChecker {
private static final Lexicon dictionary = ...;
private SpellChecker() {} // Noninstantiable
public static boolean isValid(String word) { ... }
public static List<String> suggestions(String typo) { ... }
}
- 设计为单例
// Inappropriate use of singleton - inflexible & untestable!
public class SpellChecker {
private final Lexicon dictionary = ...;
private SpellChecker(...) {}
public static INSTANCE = new SpellChecker(...);
public boolean isValid(String word) { ... }
public List<String> suggestions(String typo) { ... }
}
这两种方式下,都存在一个前置的假设,即只有一种字典可用。但是实际中,针对不同的语言可能有不同的字典。这时候可以将 dictionary
声明为非final,并提供一个方法为其设置值(这种情况即我们常说的set注入,即为dictionary提供一个set方法,这里不提供代码实现)。这种情况下,可能存在一个问题,这里的两种实现方法下的类中都存在静态变量,在并发环境下都会出现线程安全问题。实际可以考虑将这个类中的方法改为非静态,对其中的dictionary属性采用依赖注入的方式实现。
// 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) { ... }
}
这里采用的是构造方法的形式注入,同样的可以使用set注入。