它是不好的做法,做一个二传手回报“这个”?(Is it bad practice to make a

2019-06-21 05:39发布

它是一个好或坏的主意,以在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:

我不认为有什么特别不妥之处,它只是一个风格问题。 这是当有用:

  • 您需要一次设置多个领域(包括在建)
  • 你知道你需要设置在你写代码的时间的字段,以及
  • 有针对许多不同的组合,你要设置的字段。

替代这种方法可能是:

  1. 一个大型构造(缺点:可能会通过大量的空或默认值,而且它变得很难知道哪个值对应于什么)
  2. 一些重载的构造函数(缺点:一旦你超过几有更多获得笨拙)
  3. 工厂/静态方法(缺点:同重载的构造函数 - 获取笨重一旦有以上几个)

如果你只打算在同一时间设置的一些属性我会说这是不值得返回“这个”。 这当然倒下,如果你以后决定返回别的东西,像一个状态/成功指标/消息。



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::setMyValueBiConsumer<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”?