让java中的setter返回“this”是好还是坏?

public Employee setName(String name){
   this.name = name;
   return this;
}

这个模式很有用,因为你可以像这样设置链:

list.add(new Employee().setName("Jack Sparrow").setId(1).setFoo("bacon!"));

而不是这样:

Employee e = new Employee();
e.setName("Jack Sparrow");
...and so on...
list.add(e);

...但这有点违背标准惯例。我认为这是值得的因为它可以让setter做一些其他有用的事情。我曾在一些地方看到过这种模式(例如JMock、JPA),但它似乎并不常见,而且通常只用于定义良好的api,在这些api中这种模式随处可见。

更新:

我所描述的显然是有效的,但我真正想要的是一些关于这是否被普遍接受的想法,以及是否存在任何陷阱或相关的最佳实践。我知道Builder模式,但它比我所描述的要复杂一些——正如Josh Bloch所描述的,有一个用于对象创建的相关静态Builder类。


当前回答

这一点也不坏。但是它与JavaBeans Spec不兼容。

有很多规范依赖于这些标准访问器。

你总能让它们共存。

public class Some {
    public String getValue() { // JavaBeans
        return value;
    }
    public void setValue(final String value) { // JavaBeans
        this.value = value;
    }
    public String value() { // simple
        return getValue();
    }
    public Some value(final String value) { // fluent/chaining
        setValue(value);
        return this;
    }
    private String value;
}

现在我们可以一起用了。

new Some().value("some").getValue();

下面是另一个版本的不可变对象。

public class Some {

    public static class Builder {

        public Some build() { return new Some(value); }

        public Builder value(final String value) {
            this.value = value;
            return this;
        }

        private String value;
    }

    private Some(final String value) {
        super();
        this.value = value;
    }

    public String getValue() { return value; }

    public String value() { return getValue();}

    private final String value;
}

现在我们可以这么做了。

new Some.Builder().value("value").build().getValue();

其他回答

因为它不返回void,所以它不再是一个有效的JavaBean属性setter。如果您是世界上使用可视化“Bean Builder”工具的7个人之一,或者是使用JSP-bean-setProperty元素的17个人之一,那么这可能很重要。

至少在理论上,它会通过在调用之间设置错误的依赖关系而破坏JVM的优化机制。

它被认为是语法糖,但实际上会在超级智能的Java 43虚拟机中产生副作用。

这就是为什么我投反对票,不要使用它。

如果我正在编写一个API,我使用“return this”来设置只会设置一次的值。如果我有任何其他值,用户应该能够改变,我使用标准的void setter代替。

然而,在我看来,这真的是一个偏好问题,链式设置器看起来确实很酷。

这种特殊的模式称为方法链接。维基百科的链接,这有更多的解释和例子,如何在各种编程语言中完成。

附注:只是想把它留在这里,因为我正在寻找具体的名字。

如果你不想从setter返回'this',但又不想使用第二个选项,你可以使用下面的语法来设置属性:

list.add(new Employee()
{{
    setName("Jack Sparrow");
    setId(1);
    setFoo("bacon!");
}});

顺便说一句,我认为它在c#中略干净:

list.Add(new Employee() {
    Name = "Jack Sparrow",
    Id = 1,
    Foo = "bacon!"
});