第二章 创建和销毁对象
第四条 通过私有构造器强化不可实例化的能力
静态工具类不需要被实例化,因此将这个类的构造方法声明为私有的。
(这一条比较简单,跳过)
第五条 优先考虑依赖注入来引用资源
有许多类会依赖一个或多个底层的资源。
一 将资源依赖注入
以一个拼写检查器类举例,拼写检查器需要依赖词典:
下面是两个不合适的做法(静态工具类和Singleton):
/*拼写检查器类 将词典作为静态工具类*/
public class SpellChecker {
//需要依赖的词典 静态工具类
private static final Lexicon dictionary = ...;
private SpellChecker() {
}
}
/*拼写检查器类 Singleton*/
public class SpellChecker {
//需要依赖的词典
private final Lexicon dictionary = ...;
public static INSTANCE = new SpellChecker(...);
private SpellChecker(...) {
}
}
这样词典就会被写死在拼写检查器类中。
下面是推荐的做法(依赖注入):
/*拼写检查器类 依赖注入*/
public class SpellChecker {
//需要依赖的词典
private final Lexicon dictionary;
//在构造方法中注入
public SpellChecker(Lexicon dictionary) {
this.dictionary = Objects.requireNonNull(dictionary);
}
}
当创建一个新的实例时,就将该资源传到构造方法中。
这就是依赖注入(DI)的一种形式:词典是拼写检查器的一个依赖(dependency),在创建拼写检查器时就将词典注入(injected)其中。
依赖注入的对象资源具有不可变性,多个客户端可以共享依赖对象。
二 将资源工厂依赖注入
在Java8中增加的接口Supplier<T>,最适合用于表示工厂(下次深入了解一下)。
带有Supplier<T>的方法,应该限制输出工厂的类型参数使用有限制的通配符类型(详见第31条),以便客户端能够传入一个工厂,来创建指定类型的任意子类型。
例如下面是一个生产马赛克的方法:
//生产马赛克方法
Mosaic create(Supplier<? extends Tile> tileFactory){
...
}
三 依赖注入框架
虽然依赖注入极大地提升了灵活性和可测试性,但会导致大型项目凌乱不堪(通常包含上千个依赖)。
这时就可以利用依赖注入框架来解决,如Spring、Dagger或Guice。
四 总结
不要用静态工具类或Singleton来实现依赖。
应该使用依赖注入,将这些资源或工厂传给构造方法,提高类的灵活性、可重用性和可测试性。