来自" Dependency Injection with Guice"的一个简单例子打破了德米特的定律。"至少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的流利感到满意?
此外,我阅读了文章,并发布了关于流利的界面和德米特法则。只有少数文章,显然不是来自主流人。他们中的一些人写道,流利是好的,这里必须违反得墨忒耳法,其中一些人写道,流利的界面很糟糕,有些人写道,流利不违反得墨忒耳法则。社区没有严格的愿景。
不过,这个问题是关于Guice的,不是关于&#34;流利的&#34;界面一般。
答案 0 :(得分:4)
此类&#34;编码规则&#34;检查工具......是关于执行规则。
他们带来了一个默认规则集,但使用这些工具的本质是:他们应该做想要他们要做的事情。
换句话说:我们无法告诉您什么是适合您的。如果你;并且使用此工具的团队同意:&#34;我们理解这个警告;我们认为它可以很好地压制它&#34 ;;那你就定了。你不需要SO社区的支持;你希望负责你的项目的人同意&#34;正确的事情&#34;。
唯一的&#34;真实&#34;我在这里看到的问题:决定是否要将大量此类抑制注释推送到您的代码中;或者你应该改为调整PMD规则集。
还有一些个人的2分:我确实认为&#34; demeter&#34;真是一个重要的导入规则。我正在使用python的小cmdline工具;我最初违反了LoD--故意。 3天后,我开始后悔这个决定。但是看看你的代码示例;我会不声明这是一个值得思考的LoD违规(所以:压制对我来说没问题)。
答案 1 :(得分:2)
或者,是否有人对Guice的流利感到满意?
Javadoc中提到了Binding
(强调我的)的流畅界面的意图:
Guice使用嵌入式特定于域的语言(EDSL)来帮助您创建 和可读的绑定。
流畅的语法有一个很大的好处,就是你得到的简单的绑定器代码读取几乎就像自然语言一样:
bind(TransactionLog.class).to(DatabaseTransactionLog.class);
在软件工程中,您通常需要在做出决策时平衡优点和缺点。再次从同一个javadoc中读取:
这种方法(EDSL)非常适合整体可用性,但它的成本很低:通过读取方法级javadoc很难学习如何使用Binding EDSL
它继续确认流利语法的一个缺点,即Binder
javadoc变得稍微不透明。可能违反“得墨忒耳法”的另一个缺点。
此外,我阅读了文章,并发布了关于流利的界面和德米特法则。只有少数文章,显然不是来自主流人。他们中的一些人写道,流利是好的,这里必须违反得墨忒耳法,其中一些人写道,流利的界面很糟糕,有些人写道,流利不违反得墨忒耳法则。社区没有严格的愿景。
就这样吧!有可能存在适合不同倾向的多种方法。
你应该注意关于C#中的扩展方法是否违反封装的类似争论。请参阅this answer from Jon Skeet,并提供Eric Lippert的精彩报价。
答案 2 :(得分:2)
一个流畅的API 不必然违反Demeter法,因为并非所有的链调用都违反了Demeter法。
Demeter法则声明您可以访问您所在对象内的任何内容,您获得的方法参数,或在通话期间创建的任何对象。
因此:
bind(TransactionLog.class).to(DatabaseTransactionLog.class)
很好。你没有得到以前的任何东西,你创建一个新的绑定。解除引用适用于(可能)新对象(新的绑定构建器或其他)。
Demeter法则基本上规定您不应访问其他对象的内部字段。只要您不这样做,只要您愿意,您就可以拥有一个呼叫链。