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


当前回答

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

其他回答

我过去更喜欢这种方法,但我已经决定不这么做了。

原因:

可读性。将每个setFoo()放在单独的行上可以使代码更具可读性。通常情况下,您阅读代码的次数要比编写代码的次数多得多。 副作用:setFoo()应该只设置字段foo,没有其他。返回this是一个额外的“WHAT was that”。

我看到的Builder模式没有使用setFoo(foo). setbar (bar)约定,而是使用了更多的foo(foo).bar(bar)。也许正是出于这些原因。

这总是一个品味问题。我只是喜欢“最少惊喜”的方法。

这不是坏习惯。这是一种越来越普遍的做法。大多数语言不需要你处理返回的对象,如果你不想这样做,所以它不会改变“正常”setter使用语法,但允许你将setter链接在一起。

这通常被称为构建器模式或流畅接口。

它在Java API中也很常见:

String s = new StringBuilder().append("testing ").append(1)
  .append(" 2 ").append(3).toString();

一般来说,这是一个很好的实践,但是你可能需要使用布尔类型来确定操作是否成功完成,这也是一种方法。一般来说,没有教条说这是好的还是床上的,它当然来自于情况。

如果可用,最好使用其他语言结构。例如,在Kotlin中,您可以使用with、apply或let。如果使用这种方法,实际上不需要从setter返回实例。

这种方法允许你的客户端代码:

对返回类型漠不关心 更容易维护 避免编译器的副作用

这里有一些例子。

val employee = Employee().apply {
   name = "Jack Sparrow"
   id = 1
   foo = "bacon"
}


val employee = Employee()
with(employee) {
   name = "Jack Sparrow"
   id = 1
   foo = "bacon"
}


val employee = Employee()
employee.let {
   it.name = "Jack Sparrow"
   it.id = 1
   it.foo = "bacon"
}

它不仅打破了getter /setter的惯例,还打破了Java 8方法参考框架。MyClass::setMyValue是一个BiConsumer<MyClass,MyValue>, myInstance::setMyValue是一个Consumer<MyValue>。如果你让你的setter返回这个,那么它就不再是Consumer<MyValue>的有效实例,而是Function<MyValue,MyClass>,并且会导致任何使用这些setter的方法引用(假设它们是void方法)的事情中断。