它是一个好或坏的主意,以在Java回报“这个”制定者?
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模式,但它是一个涉及多一点,然后我所描述 - 作为乔希布洛赫所描述的那样有创建对象相关的静态生成器类。
Answer 1:
我不认为有什么特别不妥之处,它只是一个风格问题。 这是当有用:
- 您需要一次设置多个领域(包括在建)
- 你知道你需要设置在你写代码的时间的字段,以及
- 有针对许多不同的组合,你要设置的字段。
替代这种方法可能是:
- 一个大型构造(缺点:可能会通过大量的空或默认值,而且它变得很难知道哪个值对应于什么)
- 一些重载的构造函数(缺点:一旦你超过几有更多获得笨拙)
- 工厂/静态方法(缺点:同重载的构造函数 - 获取笨重一旦有以上几个)
如果你只打算在同一时间设置的一些属性我会说这是不值得返回“这个”。 这当然倒下,如果你以后决定返回别的东西,像一个状态/成功指标/消息。
Answer 2:
这不是不好的做法。 这是一个越来越普遍的做法。 大多数语言并不需要你来处理返回的对象,如果你不想因此它不改变“正常”二传手使用语法,但允许您链制定者在一起。
这通常被称为一个生成器模式或流畅的界面 。
这也是常见的Java API中:
String s = new StringBuilder().append("testing ").append(1)
.append(" 2 ").append(3).toString();
Answer 3:
总结:
- 它被称为“流畅接口”,或“方法链”。
- 这是不是“标准”的Java,虽然你做多了更多的看到这些天(在jQuery的伟大工程)
- 它违反了JavaBean的规范,所以它会用各种工具和库,特别是JSP建设者和春假。
- 它可能会阻止一些优化的JVM通常会做
- 有些人认为它清除代码时,有些人认为这是“可怕”
未提及的其他几个要点:
这违反了每个函数应该做一个(也是唯一一个)的事情本金。 您可能会或在此可能不相信,但在Java中,我相信它工作得很好。
IDE也不会产生这些对您(默认情况下)。
我终于,这里有一个真实世界的数据点。 我曾经使用内置这样的库的问题。 Hibernate的查询生成器就是这样在现有库的例子。 由于查询的一组*方法返回的查询,这是不可能的只是看着签名如何使用它来告诉。 例如:
Query setWhatever(String what);
这带来了模棱两可的:它的方法修改当前的对象(你的模式),或者,也许查询确实是不可变的(一个非常受欢迎的和有价值的模式),并且该方法返回一个新的。 它只是使图书馆的使用难度,许多程序员不利用这个功能。 如果setter方法是制定者,它会更清楚如何使用它。
Answer 4:
我更喜欢使用“与”这个方法:
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!"));
Answer 5:
如果你不希望返回'this'
从模子,但不希望使用您可以使用以下语法设置属性的第二个选项:
list.add(new Employee()
{{
setName("Jack Sparrow");
setId(1);
setFoo("bacon!");
}});
顺便说一句,我认为它在C#中稍微干净:
list.Add(new Employee() {
Name = "Jack Sparrow",
Id = 1,
Foo = "bacon!"
});
Answer 6:
它不仅打破了getter / setter方法的惯例,也打破了Java 8方法参考框架。 MyClass::setMyValue
是BiConsumer<MyClass,MyValue>
,和myInstance::setMyValue
是一个Consumer<MyValue>
。 如果你有你的二传手返回this
,那么它不再是一个有效的实例Consumer<MyValue>
,而是一个Function<MyValue,MyClass>
,并使用方法引用到那些制定者(假设他们都是无效的方法),打破造成什么。
Answer 7:
我不知道Java,但我已经在C ++中做到了这一点。 其他人说,这使得线路很长,真正难读,但我已经做了这样的很多次:
list.add(new Employee()
.setName("Jack Sparrow")
.setId(1)
.setFoo("bacon!"));
这是更好的:
list.add(
new Employee("Jack Sparrow")
.Id(1)
.foo("bacon!"));
至少,我认为。 不过,欢迎您downvote我,打电话给我,如果你想一个可怕的程序员。 我不知道你是否允许甚至为此在Java中。
Answer 8:
该方案(双关语意),称为“流畅接口”,现在变得很流行。 这是可以接受的,但它不是我的那杯茶。
Answer 9:
因为它不返回void,它不再是一个有效的JavaBean的属性设置。 如果你使用Visual“豆生成器”工具,七人在世界上的一个,或17使用JSP-豆的setProperty元素中的一个可能无关紧要。
Answer 10:
至少在理论上 ,它可以通过电话之间设置的假相关损害JVM的优化机制。
它被认为是语法糖,但实际上可以创建在超级智能的Java 43的虚拟机的副作用。
这就是为什么我投反对票,不使用它。
Answer 11:
这不是一个不好的做法都没有。 但它不是compatiable与JavaBeans规范 。
而且有很多规范的依赖于这些标准的存取。
你总是可以让他们共存于对方。
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();
Answer 12:
我赞成有“本”的回报制定者。 我不在乎,如果它不符合豆。 对我来说,如果它的好有“=”表达/语句,则返回值被罚款制定者。
Answer 13:
圣保罗阿布兰特什提供了另一种方法,使JavaBean的制定者流利的:限定了内部生成器类为每个JavaBean的。 如果您使用的是得到由返回值的制定者工具狼狈不堪,保罗的模式可能会有所帮助。
Answer 14:
我曾经喜欢这种方法,但我已决定反对。
原因:
- 可读性。 它使代码更易读让每个setFoo()在单独的行。 你平时阅读的代码很多,很多更多的时间比你写的一次。
- 副作用:setFoo()应该只设置字段富,没有别的。 返回这是一个额外的“那是什么”。
我看到不使用setFoo(富).setBar(巴)约定,但更多的富(富)的.bar(巴)Builder模式。 也许正是对于这些原因。
它一如既往一个品味的问题。 我只是喜欢“至少惊喜”的做法。
Answer 15:
这种特殊的模式称为方法链接。 维基百科的链接 ,这有更多的解释和它是如何在各种编程语言做例子。
PS:只是想离开这里吧,因为我一直在寻找的具体名称。
Answer 16:
如果您使用的整个应用程序了相同的约定似乎罚款。
在oher手,如果你的应用程序的现有部分采用标准约定我会坚持下去,并添加建设者更复杂的类
public class NutritionalFacts {
private final int sodium;
private final int fat;
private final int carbo;
public int getSodium(){
return sodium;
}
public int getfat(){
return fat;
}
public int getCarbo(){
return carbo;
}
public static class Builder {
private int sodium;
private int fat;
private int carbo;
public Builder sodium(int s) {
this.sodium = s;
return this;
}
public Builder fat(int f) {
this.fat = f;
return this;
}
public Builder carbo(int c) {
this.carbo = c;
return this;
}
public NutritionalFacts build() {
return new NutritionalFacts(this);
}
}
private NutritionalFacts(Builder b) {
this.sodium = b.sodium;
this.fat = b.fat;
this.carbo = b.carbo;
}
}
Answer 17:
乍一看:“令人恶心!”。
在进一步的思考
list.add(new Employee().setName("Jack Sparrow").setId(1).setFoo("bacon!"));
比实际容易发生错误少
Employee anEmployee = new Employee();
anEmployee.setName("xxx");
...
list.add(anEmployee);
所以,挺有意思的。 添加主意toolbag ...
Answer 18:
是的,我认为这是一个好主意。
如果我可以补充一下,关于这个问题的:
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()返回一个人,而不是一个朋友,并没有PeoplesetNickName。
我们怎么能写制定者返回,而不是类的名称SELF类?
这样的事情就可以了(如果自关键字会存在)。 这是否存在呢?
class People
{
private String name;
public SELF setName(String name)
{
this.name = name;
return this;
}
}
Answer 19:
总的来说这是一个很好的做法,但你可能需要设定型函数使用布尔类型,以确定是否操作成功或没有完成,那就是太一种方式。 在一般情况下,没有教条地说,这是好还是床,它来自的情况,当然。
Answer 20:
从声明
list.add(new Employee().setName("Jack Sparrow").setId(1).setFoo("bacon!"));
我看到两件事情
1)无意义语句。 2)可读性的缺失。
Answer 21:
这可以是少可读
list.add(new Employee().setName("Jack Sparrow").setId(1).setFoo("bacon!"));
或这个
list.add(new Employee()
.setName("Jack Sparrow")
.setId(1)
.setFoo("bacon!"));
这是方式比更具可读性:
Employee employee = new Employee();
employee.setName("Jack Sparrow")
employee.setId(1)
employee.setFoo("bacon!"));
list.add(employee);
Answer 22:
我一直在做我的制定者相当长一段时间,唯一真正的问题是,与严格的getPropertyDescriptors坚持让豆读/写豆存取库。 在这种情况下,你的java“豆”不会有你所期望的再考。
举例来说,我没有测试它是肯定的,但我不会感到惊讶,创建你的JSON /映射Java对象时,杰克逊将不会承认那些为制定者。 我希望我是错的就这一个(我将很快测试)。
事实上,我正在开发一个轻量级SQL中心ORM,我必须添加一些代码beyong getPropertyDescriptors公认的制定者返回这一点。
Answer 23:
很久以前的答案,但我的两分钱...其罚款。 我希望这流利的接口更经常地使用。
重复的“工厂”变量不下面添加更多的信息:
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(Foo.class);
factory.setFilter(new MethodFilter() { ...
这是清洁的,恕我直言:
ProxyFactory factory = new ProxyFactory()
.setSuperclass(Properties.class);
.setFilter(new MethodFilter() { ...
当然,前面已经提到的答案之一是,Java API将不得不进行调整,为某些情况下,正确地做到这一点,如继承和工具。
Answer 24:
这是更好的,如果可以使用其他语言结构。 例如,在科特林,你将与使用, 应用 ,或让 。 如果使用这种方法,你不会真的需要从你的二传手返回一个实例。
这种方法允许你的客户端代码是:
这里有些例子。
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"
}
Answer 25:
如果我写了一个API,我用“回归这”设置将只设置一次值。 如果我有一个用户应该能够更改任何其他值,我使用的是标准的制定者无效代替。
然而,它真的喜好的问题和链接setter方法看起来相当冷静,在我看来。
Answer 26:
我同意所有的海报声称这打破了JavaBeans规范。 我们有理由保留这一点,但我也觉得使用这种生成器模式(这是暗示)的有它的位置; 只要它不使用无处不在,它应该是可以接受的。 “这地方”,对我来说,就是终点是一个“建立()”方法的调用。
有设置当然所有这些事情的其他方式,但这里的好处是,它避免了1)许多参数公共构造函数和2)部分特定对象。 在这里,你有制造商收集所需的内容,然后调用它的“建立()”的结尾,这样就可以保证部分指定的对象没有被构造,因为该操作可以给出低于公众知名度。 另一种方法是“参数对象”,但恕我直言只是推动问题返回上一级。
我不喜欢很多参数的构造函数,因为他们使之更容易,很多同类型的参数传递中,它可以更容易地在错误的参数传递给参数。 我不喜欢使用大量的制定者,因为可以使用的对象完全配置好之前它。 此外,具有基于以前的选择默认值的概念是更好地与“建立()”方法提供服务。
总之,我认为这是一个很好的做法,如果使用得当。
Answer 27:
坏习惯:二传手设定一个getter GET
怎么样式声明的方法,这会为ü
setPropertyFromParams(array $hashParamList) { ... }
文章来源: Is it bad practice to make a setter return “this”?