【问题标题】:What's wrong with returning this?退货有什么问题?
【发布时间】:2013-04-17 12:39:37
【问题描述】:

在我工作的公司,有一份文档描述了我们应该在 Java 中遵守的良好实践。其中之一是避免返回 this 的方法,例如:

class Properties {

  public Properties add(String k, String v) {
   //store (k,v) somewhere
     return this;
  }

}

我会有这样的课,这样我就可以写作了:

 properties.add("name", "john").add("role","swd"). ...

这种成语我见过很多次了,比如StringBuilder,没觉得有什么问题。

他们的论点是:

... 可能是同步问题或目标对象状态预期失败的根源。

我想不出这可能是真的情况,你们谁能给我一个例子吗?

编辑该文档没有指定任何关于可变性的内容,所以我看不出链接调用和执行之间的区别:

properties.add("name", "john");
properties.add("role", "swd");

我会尝试与发起人取得联系,但我想在我的枪上膛的情况下这样做,这就是我发布问题的原因。

已解决:我与其中一位作者交谈,他的初衷显然是避免释放尚未准备好的对象,例如在 Builder 模式中,并解释说,如果上下文切换在调用之间发生,对象可能处于无效状态。我认为这与返回this 无关,因为您可能会犯同样的错误,购买一个一个调用这些方法,并且更多地与正确同步构建过程有关。他承认该文件可能会更加明确,并将很快对其进行修改。胜利是我/我们的!

【问题讨论】:

  • “同步问题”?我无法想象这将如何产生(双关语不是故意的,而是可以容忍的)。像几乎所有其他模式一样,它有很好的用途和误用,但我不明白你得到的推理。也许可以向该文件的作者寻求澄清。
  • stackoverflow.com/questions/1345001/… 上还有另一篇关于此的帖子
  • 我也不明白这种说法。
  • 如果我希望我的(假设的)下属停止做我不喜欢但不想承认我的理由是95% 审美。 (另请参阅:支持或反对 OTBC / K&R 风格的每一个论点。)
  • 如果您在两个线程中执行了buff.append("Hello, ").append("World\n"),其中buffStringBuffer,您最终可能会得到“Hello, Hello, World\nWorld\n”。但是,StringBuffer 拥有所有同步并没有多大意义,它告诉您“良好做法”。 (OTOH,返回 this 确实表明语言存在问题。)

标签: java oop this


【解决方案1】:

我的猜测是他们反对可变状态(而且通常是正确的)。如果您没有设计返回this 的流畅接口,而是返回具有更改状态的对象的新不可变实例,则可以避免同步问题或没有"failed expectations about the states of target objects"。这可以解释他们的要求。

【讨论】:

  • 您能否解释一下,从实例方法返回 this 如何影响不变性?返回对不可变对象的引用有什么不好?
【解决方案2】:

实践的唯一重要基础是避免可变对象;关于它“令人困惑”并导致“期望失败”的批评相当微弱。一个人应该永远在没有首先熟悉它的语义的情况下使用一个对象,并且仅仅为了迎合那些选择不阅读 Javadoc 的人而对 API 实施约束根本不是一个好习惯——尤其是因为,因为请注意,返回 this 以实现流畅的 API 设计是 Java 中的标准方法之一,并且确实是一种非常受欢迎的方法。

【讨论】:

    【解决方案3】:

    我认为有时这种方法非常有用,例如在“构建器”模式中。

    我可以说,在我的组织中,这种事情是由 Sonar 规则控制的,而我们没有这样的规则。

    另一个猜测是,该项目可能是在现有代码库之上构建的,这是一种遗留限制。

    所以我在这里唯一可以建议的就是与撰写此文档的人交谈 :)

    希望对你有帮助

    【讨论】:

      【解决方案4】:

      我认为在某些情况下使用该模式是完全可以接受的。

      例如,作为一名 Swing 开发人员,我经常使用 GridBagLayout,因为它具有优势和灵活性,但任何曾经使用过它的人(它是犯罪 GridBagConstraints 的合作伙伴)都知道它可能非常冗长且可读性不强。

      我在网上看到的一种常见解决方法(也是我使用的一种)是将 GridBagConstraints (GBConstraints) 子类化,它对每个不同的属性都有一个 setter,每个 setter 都会返回这个。这允许开发人员根据需要链接不同的属性。

      生成的代码大约是原来的 1/4,而且可读性/可维护性要高得多,即使对于可能不熟悉使用 GridBagConstaints 的临时开发人员也是如此。

      【讨论】:

        猜你喜欢
        • 2020-11-20
        • 2011-08-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-10-18
        • 1970-01-01
        • 2020-06-15
        • 2016-12-26
        相关资源
        最近更新 更多