让一个二传手返回“这个”是不是不好的做法?

2022-08-31 05:23:24

让java中的setter返回“this”是一个好主意还是坏主意?

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

此模式可能很有用,因为这样您就可以像这样链接 setter:

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);

...但它有点违反标准惯例。我想这可能是值得的,因为它可以使那个设置者做一些其他有用的事情。我见过这种模式在某些地方使用(例如JMock,JPA),但它似乎并不常见,并且通常仅用于定义良好的API,其中这种模式无处不在。

更新:

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


答案 1

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

这通常称为生成器模式或流畅的接口

这在Java API中也很常见:

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

答案 2

总结一下:

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

其他几点没有提到:

  • 这违反了每个函数应该做一件事(而且只有一件)的原则。你可能相信也可能不相信这一点,但在Java中,我相信它运行良好。

  • IDE 不会为您生成这些(默认情况下)。

  • 最后,这是一个真实的数据点。我在使用这样构建的库时遇到问题。Hibernate的查询构建器是现有库中的一个例子。由于Query的set*方法返回查询,因此仅通过查看签名无法判断如何使用它。例如:

    Query setWhatever(String what);
    
  • 它引入了一个歧义:该方法是否修改了当前对象(您的模式),或者,也许Query确实是不可变的(一种非常流行且有价值的模式),并且该方法正在返回一个新的模式。它只是使库更难使用,许多程序员没有利用这个功能。如果二传手是二传手,那么如何使用它就会更清楚。