使用 Guice 和 "Law of Demeter" 进行依赖注入
Dependency Injection with Guice and "Law of Demeter"
来自“Dependency Injection with Guice" break the "Law of Demeter." At least as PMD 的一个小例子。
public class BillingModule extends AbstractModule {
@Override
protected void configure() {
bind(TransactionLog.class).to(DatabaseTransactionLog.class);
bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
bind(BillingService.class).to(RealBillingService.class);
}
}
PMD 标记下一行警告 Potential violation of Law of Demeter (method chain
calls)
bind(TransactionLog.class).to(DatabaseTransactionLog.class)
是否可以使用 @SuppressWarnings("PMD.LawOfDemeter")
抑制此警告,或者我是否需要采用其他方法?
澄清
通过几个简单的方法就可以将流畅的界面转换为经典的界面:
fasten(TransactionLog.class, DatabaseTransactionLog.class);
fasten
的可能实现:
private <M, N extends M> void fasten(final Class<M> dependency, final Class<N> realization){
fastenTo(bind(dependency), realization);
}
private <M, N extends M> void fastenTo(final AnnotatedBindingBuilder<M> binder, final Class<N> realization){
binder.to(realization);
}
这不只是幻想,一些扩展 Guice 的库部分地使用了它。
例如 play.libs.akka.AkkaGuiceSupport
:
https://playframework.com/documentation/2.5.5/api/java/play/libs/akka/AkkaGuiceSupport.html
它有方法
default <T extends akka.actor.Actor> void bindActor(java.lang.Class<T> actorClass,java.lang.String name)
default <T extends akka.actor.Actor> void bindActor(java.lang.Class<T> actorClass,java.lang.String name, java.util.function.Function<akka.actor.Props,akka.actor.Props> props)
不是bindActor(actorClass).qualified(name).with(props)
而是bindActor(actorClass, name, props)
我知道 Guice 更复杂并且可以有更多的参数和组合,但是,有人创建了包装库来替换 Guice 中的流畅界面吗?有人写关于它的东西吗?或者,有人对流利的 Guice 感到满意吗?
此外,我阅读了有关流畅界面和得墨忒耳法则的文章和post。只有几篇文章,显然不是来自主流人士。有的写fluent很好,这里肯定违反Demeter法则,有的写fluent界面不好,有的写fluent不违反Demeter法则。社区没有严格的愿景。
不过,这个问题是关于 Guice,而不是一般的 "fluent" 接口。
此类 "coding rule" 检查工具...与执行规则有关。
他们带来了默认规则集,但使用此类工具的本质是:他们应该做你想要他们做的事。
换句话说:我们无法告诉您什么适合您。如果你;并且您周围使用此工具的团队同意:"we understand this warning; and we think it is fine suppressing it";那么你已经准备好了。您不需要 SO 社区的支持;您希望负责您项目的人员同意 "the right thing".
我在这里看到的唯一 "real" 问题:决定是否要将大量此类抑制注释推送到代码中;或者您是否应该调整 PMD 规则集。
还有一些个人的 2 美分:我确实认为 "law of demeter" 确实是一个重要规则。我正在使用 python 开发一个小型 cmdline 工具;我最初违反了 LoD - 是故意的。 3 天后,我已经开始后悔那个决定了。但是看看你的代码示例;我会 不会 宣布这是一个值得考虑的 LoD 违规(所以:压制对我来说没问题)。
Alternatively, is anyone happy with a fluent in Guice?
Binding
的 Javadoc 中提到了流畅界面的意图(强调我的):
Guice uses an embedded domain-specific language, or EDSL, to help you create bindings simply and readably.
流利的语法有一个很大的好处,因为您可以获得简单的活页夹代码,阅读几乎就像自然语言一样:
bind(TransactionLog.class).to(DatabaseTransactionLog.class);
在一般的软件工程中,您在做出决定时必须权衡利弊。再次从同一个 javadoc 读取:
This approach (EDSL) is great for overall usability, but it does come with a small cost: it is difficult to learn how to use the Binding EDSL by reading method-level javadocs
它继续 承认 流畅语法的一个缺点,即 Binder
javadoc 变得稍微不透明。可能违反得墨忒耳法则是另一个缺点。
Moreover, I read the articles and post about the fluent interface and the Law of Demeter. There are only a few articles and clearly not from the mainstream guys. Some of them wrote that fluent is good, and Law of Demeter must be violated here, some of them wrote that fluent interface is bad and some of them wrote that fluent does not violate the Law of Demeter. There is no strict vision by the community.
就这样吧!可能存在适合不同倾向的多种方法。
您可能应该注意到关于 C# 中的扩展方法是否违反封装的类似争论。请参阅 this answer from Jon Skeet 和 Eric Lippert 的精彩引述。
流利的 API 不一定 违反 Demeter 法则,因为并非所有链调用都违反 Demeter 法则。
Demeter 法则规定您可以访问您所在对象内部的任何内容、您获得的方法参数、或在调用期间创建的任何对象。
因此:
bind(TransactionLog.class).to(DatabaseTransactionLog.class)
可以。您不会得到以前存在的任何东西,您 创建 一个新的绑定。取消引用适用于(可能)一个新对象(一个新的绑定构建器或其他)。
Demeter 法则基本上规定您不应访问其他对象的内部字段。只要你不那么做,你可以有一个调用链,只要你喜欢。
来自“Dependency Injection with Guice" break the "Law of Demeter." At least as PMD 的一个小例子。
public class BillingModule extends AbstractModule {
@Override
protected void configure() {
bind(TransactionLog.class).to(DatabaseTransactionLog.class);
bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
bind(BillingService.class).to(RealBillingService.class);
}
}
PMD 标记下一行警告 Potential violation of Law of Demeter (method chain
calls)
bind(TransactionLog.class).to(DatabaseTransactionLog.class)
是否可以使用 @SuppressWarnings("PMD.LawOfDemeter")
抑制此警告,或者我是否需要采用其他方法?
澄清
通过几个简单的方法就可以将流畅的界面转换为经典的界面:
fasten(TransactionLog.class, DatabaseTransactionLog.class);
fasten
的可能实现:
private <M, N extends M> void fasten(final Class<M> dependency, final Class<N> realization){
fastenTo(bind(dependency), realization);
}
private <M, N extends M> void fastenTo(final AnnotatedBindingBuilder<M> binder, final Class<N> realization){
binder.to(realization);
}
这不只是幻想,一些扩展 Guice 的库部分地使用了它。
例如 play.libs.akka.AkkaGuiceSupport
:
https://playframework.com/documentation/2.5.5/api/java/play/libs/akka/AkkaGuiceSupport.html
它有方法
default <T extends akka.actor.Actor> void bindActor(java.lang.Class<T> actorClass,java.lang.String name)
default <T extends akka.actor.Actor> void bindActor(java.lang.Class<T> actorClass,java.lang.String name, java.util.function.Function<akka.actor.Props,akka.actor.Props> props)
不是bindActor(actorClass).qualified(name).with(props)
而是bindActor(actorClass, name, props)
我知道 Guice 更复杂并且可以有更多的参数和组合,但是,有人创建了包装库来替换 Guice 中的流畅界面吗?有人写关于它的东西吗?或者,有人对流利的 Guice 感到满意吗?
此外,我阅读了有关流畅界面和得墨忒耳法则的文章和post。只有几篇文章,显然不是来自主流人士。有的写fluent很好,这里肯定违反Demeter法则,有的写fluent界面不好,有的写fluent不违反Demeter法则。社区没有严格的愿景。
不过,这个问题是关于 Guice,而不是一般的 "fluent" 接口。
此类 "coding rule" 检查工具...与执行规则有关。
他们带来了默认规则集,但使用此类工具的本质是:他们应该做你想要他们做的事。
换句话说:我们无法告诉您什么适合您。如果你;并且您周围使用此工具的团队同意:"we understand this warning; and we think it is fine suppressing it";那么你已经准备好了。您不需要 SO 社区的支持;您希望负责您项目的人员同意 "the right thing".
我在这里看到的唯一 "real" 问题:决定是否要将大量此类抑制注释推送到代码中;或者您是否应该调整 PMD 规则集。
还有一些个人的 2 美分:我确实认为 "law of demeter" 确实是一个重要规则。我正在使用 python 开发一个小型 cmdline 工具;我最初违反了 LoD - 是故意的。 3 天后,我已经开始后悔那个决定了。但是看看你的代码示例;我会 不会 宣布这是一个值得考虑的 LoD 违规(所以:压制对我来说没问题)。
Alternatively, is anyone happy with a fluent in Guice?
Binding
的 Javadoc 中提到了流畅界面的意图(强调我的):
Guice uses an embedded domain-specific language, or EDSL, to help you create bindings simply and readably.
流利的语法有一个很大的好处,因为您可以获得简单的活页夹代码,阅读几乎就像自然语言一样:
bind(TransactionLog.class).to(DatabaseTransactionLog.class);
在一般的软件工程中,您在做出决定时必须权衡利弊。再次从同一个 javadoc 读取:
This approach (EDSL) is great for overall usability, but it does come with a small cost: it is difficult to learn how to use the Binding EDSL by reading method-level javadocs
它继续 承认 流畅语法的一个缺点,即 Binder
javadoc 变得稍微不透明。可能违反得墨忒耳法则是另一个缺点。
Moreover, I read the articles and post about the fluent interface and the Law of Demeter. There are only a few articles and clearly not from the mainstream guys. Some of them wrote that fluent is good, and Law of Demeter must be violated here, some of them wrote that fluent interface is bad and some of them wrote that fluent does not violate the Law of Demeter. There is no strict vision by the community.
就这样吧!可能存在适合不同倾向的多种方法。
您可能应该注意到关于 C# 中的扩展方法是否违反封装的类似争论。请参阅 this answer from Jon Skeet 和 Eric Lippert 的精彩引述。
流利的 API 不一定 违反 Demeter 法则,因为并非所有链调用都违反 Demeter 法则。
Demeter 法则规定您可以访问您所在对象内部的任何内容、您获得的方法参数、或在调用期间创建的任何对象。
因此:
bind(TransactionLog.class).to(DatabaseTransactionLog.class)
可以。您不会得到以前存在的任何东西,您 创建 一个新的绑定。取消引用适用于(可能)一个新对象(一个新的绑定构建器或其他)。
Demeter 法则基本上规定您不应访问其他对象的内部字段。只要你不那么做,你可以有一个调用链,只要你喜欢。