让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类。
总结:
它被称为“流畅接口”或“方法链接”。
这不是“标准”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.
是的,我认为这是个好主意。
如果我能补充点什么,关于这个问题:
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;
}
}
我同意所有声称这破坏了JavaBeans规范的帖子。有理由保留这一点,但我也觉得使用这个构建器模式(上面提到的)有它的一席之地;只要不是到处都用,就应该是可以接受的。对我来说,“It’s Place”的终点是对“build()”方法的调用。
There are other ways of setting all these things of course, but the advantage here is that it avoids 1) many-parameter public constructors and 2) partially-specified objects. Here, you have the builder collect what's needed and then call its "build()" at the end, which can then ensure that a partially-specified object is not constructed, since that operation can be given less-than-public visibility. The alternative would be "parameter objects", but that IMHO just pushes the problem back one level.
我不喜欢多形参构造函数,因为它们更有可能传入大量相同类型的实参,从而更容易将错误的实参传递给形参。我不喜欢使用大量的setter,因为对象可以在完全配置之前使用。此外,使用“build()”方法更好地实现基于先前选择的默认值的概念。
总之,我认为这是一个很好的实践,如果使用得当。