欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Guice随笔 C#CC++SpringEclipse 

程序员文章站 2022-07-14 14:45:21
...
随着时间的推移. 当初吵翻了天的依赖注入再也不是什么新鲜玩意儿.

在日复一日给资本家拉磨的平淡中, Spring和自己写的小玩具也都被扔在记忆的垃圾堆里不必提起. 对Guice的激情也逐渐磨灭到麻木和冷淡了.

日常一些邮件列表中, 仍然能看到对使用Guice之类框架的反感或者死忠的两种截然不同的观点碰撞, 甚至于是否使用依赖注入也仍然没有尘埃落定.

个人从前是依赖注入的坚定粉丝, 也是Guice的欢呼者. 到现在我在需要使用一个框架的时候还是会使用Guice, 但是, 各位看官, 如果你们以前曾经见过那个挥舞着Guice超级大棒见什么都砸几下的不屈身影, 他已经移民去火星了.

如今, 我理想的使用Guice的方法. 就是说我有一堆类, 互相有依赖关系, 假设A依赖B, C, D; B依赖X, Y, Z; C依赖于D, B和D需要是Singleton, 那么就写成:
class A {
  @Inject A(B b, C c, D d) {...}
}

@Singleton
class B {
  @Inject B(X x, Y y, Z z) {...}
}

class C {
  @Inject C(D d) {...}
}

@Singleton
class D {
  @Inject D(...) {}
}


如果你对Guice熟悉的话, 就会看出来这正是Guice幼儿园小班级别的代码啊.

这就对了, 几年用下来的经验告诉我, Guice对这种最简单的情况的处理方式是最简单, 最直接的. 不需要写什么Module, 不需要什么binding, 那些东西带来太多的复杂性.

很多对依赖注入或者Guice的疑虑主要集中在代码不容易理解, 依赖关系被隐藏在Module中不容易发现等等. 但是我发现这些疑虑在尽量有意减少module和binding的前提下, 都不再是问题.

比如我在读A类的代码, 需要知道B到底是怎么回事, 直接一个F3(Eclipse), 就到了B的代码里面. 然后需要知道X是怎么回事, 再一个F3. 许多在线代码检查工具也支持这种简单的导航.

相比之下, 手工注入(就是说, 某个地方你需要手工调用new A(b, c, d))反而难于理解, 因为我还要去找new A()在什么地方调用的, B, C, D都是怎么传递进来的.

当然, 这个前提是我的B, C, D, X, Y, Z都是类而不是interface. 我发现在一个大的代码库里, interface很多时候是有害的. 因为它们人为的增加了一个间接层, 增大了跟踪导航阅读代码的难度. 在加上在Guice里你就需要额外的Module, 额外的binding, 额外的@ForApple, @ForOrange的注解, 然后Module多了, 你就要面对如何管理整个项目, 怎么样在不同的main()函数里选择不同的Module, 而又避免不能把一个Module通过不同的父Module安装两遍等等复杂讨厌的问题.

interface只有在真正存在那么一个自然的抽象的情况下才是适合的. 比如, 一个List和ArrayList就是两个不同的抽象. java.sql.Connection和任何特定的Connection实现也是两个不同的抽象.

而如果你需要写一个User, Authenticator, 或者TaskMonitor, 直接写就是了. 不管三七二十一上来先一个IUser接口加一个User实现, 或者一个User接口加一个UserImpl实现, 那就是人为增加的复杂性. 类和接口命名的尴尬雷同就已经表明这根本不是一个自然的抽象.

okay, 理想如此, 事实上当然不可能永远都没有一个接口, 两个实现的情况出现. 不过, 如果Module和binding只在有这种需求的时候才写的话, Guice代码也还可以相对容易地管理和理解. (当然, 还要小心robot leg问题的出现, 然后如果你用assistedinject来绕过这个问题的话, 又是一些额外的复杂性需要管理和维护了).

嗯, 嗯. 大致就随笔到这里. 回头我还会写写为什么我不喜欢assistedinject, 以及为什么Guice的Module会难以管理等等.