Guice的依赖注入和Demeter的定律"

时间:2017-04-19 10:42:06

标签: java guice pmd law-of-demeter

来自" 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;界面一般。

3 个答案:

答案 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法则基本上规定您不应访问其他对象的内部字段。只要您不这样做,只要您愿意,您就可以拥有一个呼叫链。