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


当前回答

如果可用,最好使用其他语言结构。例如,在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"
}

其他回答

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

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

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

它在Java API中也很常见:

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

总结:

它被称为“流畅接口”或“方法链接”。 这不是“标准”Java,尽管你现在看到的越来越多(在jQuery中工作得很好) 它违反了JavaBean规范,因此它将与各种工具和库分开,特别是JSP构建器和Spring。 它可能会阻止JVM通常会做的一些优化 一些人认为它能清理代码,另一些人认为它“可怕”

还有一些没有提到的要点:

This violates the principal that each function should do one (and only one) thing. You may or may not believe in this, but in Java I believe it works well. IDEs aren't going to generate these for you (by default). I finally, here's a real-world data point. I have had problems using a library built like this. Hibernate's query builder is an example of this in an existing library. Since Query's set* methods are returning queries, it's impossible to tell just by looking at the signature how to use it. For example: Query setWhatever(String what); It introduces an ambiguity: does the method modify the current object (your pattern) or, perhaps Query is really immutable (a very popular and valuable pattern), and the method is returning a new one. It just makes the library harder to use, and many programmers don't exploit this feature. If setters were setters, it would be clearer how to use it.

我不认为这有什么特别的问题,这只是风格的问题。它在以下情况下很有用:

您需要一次设置多个字段(包括在构建时) 您知道在编写代码时需要设置哪些字段 对于想要设置的字段,有许多不同的组合。

这种方法的替代方法可能是:

一个mega构造函数(缺点:你可能会传递很多空值或默认值,并且很难知道哪个值对应什么) 几个重载的构造函数(缺点:一旦你有多个构造函数,就会变得笨拙) 工厂方法/静态方法(缺点:与重载构造函数相同——一旦超过几个就会变得笨拙)

如果你一次只设置几个属性,我会说不值得返回this。如果您稍后决定返回其他内容,例如状态/成功指示符/消息,那么它肯定会崩溃。

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

重复'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必须进行调整,以便在某些情况下(如继承和工具)正确执行此操作。