前言
《Effective Java》中文第三版,是一本关于Java基础的书,这本书不止一次有人推荐我看。其中包括我很喜欢的博客园博主五月的仓颉,他曾在自己的博文《给Java程序猿们推荐一些值得一看的好书》中也推荐过。加深自己的记忆,同时向优秀的人看齐,决定在看完每一章之后,都写一篇随笔。如果有写的不对的地方、表述的不清楚的地方、或者其他建议,希望您能够留言指正,谢谢。
《Effective Java》中文第三版在线阅读链接:https://github.com/sjsdfg/effective-java-3rd-chinese/tree/master/docs/notes
是什么
硬连接资源,我们可以理解为,一个类,依赖其它基础类,但是过于理想化,指定了它只连接一个基础类。例如我们有一个工具类:拼音检查器,它可以检查拼音是否正确,那么我们的字典里是有所有拼音的,可以给我们提供一个基础的检查数据,当我们用硬连接资源的方式去思考时,这个拼音检查器的基础数据只由《新华字典》提供。是不是感觉这是不合理的,因为每种语言都有自己的字典,数据只由《新华字典》来提供的话,感觉是不灵活,并且单一的。
哪里用
当一个类依赖一个或其他多个底部资源类的时候,我们可以考虑使用依赖注入优先于硬连接资源。
怎么实现
我们使用一个字典检查的工具类来进行实例。
- 使用静态方法来替代硬连接资源,这种方式是不灵活,并且不能够测试的。代码实现如下:
/** * 通过静态方法来替代硬资源连接 * * @author gongguowei01@gmail.com * @since 2020-01-12 */ public class SpellChecker { //仅提供了一个资源 private static final Lexicon dictionary = "依赖的资源"; //私有构造方法,非实例化 private SpellChecker() { } //拼音检查器提供给外部类调用的方法 public static boolean isValid(String word) { return true; } }
- 使用单例来替代硬连接资源,同样也是不灵活的
/** * 使用单例来替代硬连接资源 * * @author gongguowei01@gmail.com * @since 2020-01-12 */ public class SpellChecker02 { private final Lexicon dictionary = "依赖的资源"; public static NSTANCE = new SpellChecker02(); private SpellChecker02() { } //拼音检查器提供给外部类调用的方法 public static boolean isValid(String word) { return true; } }
- 使用依赖注入替代硬连接资源,依赖注入提供了灵活性和可测试性。虽然下方的实例仍是一个基础资源,但是它由外部类提供,这样保证了我们的SepllChecker提供的功能不变,但是数据却是灵活多变的。
/** * 使用依赖注入替代硬资源连接 * * @author gongguowei01@gmail.com * @since 2020-01-12 */ public class SpellChecker03 { private final Lexicon dictionary; //需要检查什么资源,由外部类提供基础的数据 public SpellChecker03(Lexicon dictionary) { this.dictionary = Objects.requireNonNull(dictionary); } public boolean isValid(String word) { ... } }
总结
不要用单例和静态方法类来实现依赖一个或多个底层资源的类,且该资源的行为会影响到该类的行为,需要使用一个或多个底部资源类的一个类,静态方法、单例来实现是不适合的,因为它们不够灵活,也不能够测试。使用静态方法,我们如果希望它能够使用一个以上的底部资源类,我们可以通过使 dictionary
属性设置为非 final
,并添加一个方法来更改现有拼写检查器中的字典,从而让SpellChecker
支持多个字典,但这感觉是笨拙的。使用依赖注入来实现硬资源连接,也有一定的弊端,一般大型的项目,可能有数千个依赖项,这让我们的项目变得混乱,不过我们可以使用Spring框架来消除这些混乱。依赖注入,它极大地提升了类的灵活性、可重用性和可测试性。