让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类。


当前回答

很久以前的答案,但我的两分钱…这是很好的。我希望这个流畅的界面被更多地使用。

重复'factory'变量不会在下面添加更多信息:

ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(Foo.class);
factory.setFilter(new MethodFilter() { ...

恕我直言,这个更干净:

ProxyFactory factory = new ProxyFactory()
.setSuperclass(Properties.class);
.setFilter(new MethodFilter() { ...

当然,正如前面提到的答案之一,Java API必须进行调整,以便在某些情况下(如继承和工具)正确执行此操作。

其他回答

这个方案(双关语),称为“流畅界面”,现在变得非常流行。还可以接受,但不是我的菜。

这一点也不坏。但是它与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();

我更喜欢使用“with”方法:

public String getFoo() { return foo; }
public void setFoo(String foo) { this.foo = foo; }
public Employee withFoo(String foo) {
  setFoo(foo);
  return this;
}

因此:

list.add(new Employee().withName("Jack Sparrow")
                       .withId(1)
                       .withFoo("bacon!"));

警告:此withX语法通常用于为不可变对象提供“setter”,因此这些方法的调用者可能合理地期望它们创建新对象,而不是改变现有实例。也许更合理的措辞应该是:

list.add(new Employee().chainsetName("Jack Sparrow")
                       .chainsetId(1)
                       .chainsetFoo("bacon!"));

使用chainsetXyz()命名约定,几乎每个人都应该满意。

是的,我认为这是个好主意。

如果我能补充点什么,关于这个问题:

class People
{
    private String name;
    public People setName(String name)
    {
        this.name = name;
        return this;
    }
}

class Friend extends People
{
    private String nickName;
    public Friend setNickName(String nickName)
    {
        this.nickName = nickName;
        return this;
    }
}

这是可行的:

new Friend().setNickName("Bart").setName("Barthelemy");

Eclipse将不接受这一点!:

new Friend().setName("Barthelemy").setNickName("Bart");

这是因为setName()返回People而不是Friend,并且没有PeoplesetNickName。

我们如何编写setter来返回SELF类而不是类名呢?

这样就可以了(如果SELF关键字存在的话)。这真的存在吗?

class People
{
    private String name;
    public SELF setName(String name)
    {
        this.name = name;
        return this;
    }
}

我制作setter已经有一段时间了,唯一真正的问题是库坚持使用严格的getPropertyDescriptors来获得bean读取器/写入器bean访问器。在这些情况下,您的java“bean”将没有您所期望的写入器。

例如,我还没有测试它的确定,但我不会感到惊讶,杰克逊不会识别这些设置时,从json/maps创建java对象。我希望我在这一点上是错的(我很快就会测试它)。

事实上,我正在开发一个轻量级的以SQL为中心的ORM,我必须在getPropertyDescriptors之外添加一些代码来识别返回此的设置器。