6

我正在阅读Java 7 预览演示文稿 (pdf),并且有一张关于Chained Invocation的幻灯片。这是幻灯片中使用的示例:

// Construction with setters
DrinkBuilder margarita = new DrinkBuilder();
margarita.add("tequila");
margarita.add("orange liqueur");
margarita.add("lime juice");
margarita.withRocks();
margarita.withSalt();
Drink drink = margarita.drink();

// Construction with chained invocation
Drink margarita = new DrinkBuilder()
    .add("tequila")
    .add("orange liqueur")
    .add("lime juice")
    .withRocks()
    .withSalt()
    .drink();

我对此有复杂的感觉。不应该将太多的方法调用链接到一个语句中。另一方面,写作margarita.this()margarita.that()不太方便。

现在,我从 Delphi 世界来到 Java。在 Delphi 中有with语言结构。这是少数人所珍视的,而许多人则厌恶这一点(或者相反?)。我发现with它比链式调用的想法更优雅(我相信它的工作原理是void方法返回对已调用它的对象的引用——这是我不喜欢的部分,因为void应该什么都不返回)。

我很欣赏withJava 采用的语言特性,因此示例代码可以这样编写:

Drink margarita = null;
with (new DrinkBuilder()) {
    add("tequila");
    add("orange liqueur");
    add("lime juice");
    withRocks();
    withSalt();
    margarita = drink();
}

我是唯一一个更喜欢这种解决方案而不是链式调用的人吗?还有其他人觉得这with可能是对 Java 语言的有用扩展吗?(让我想起有人关于需要“Java++”的问题......)

4

6 回答 6

13

可以使用带有初始化程序的匿名类在 Java 中翻译with语句:

Drink margarita = new DrinkBuilder() {{
    add(“tequila”);
    add(“orange liqueur”);
    add(“lime juice”);
    withRocks();
    withSalt();
}}.drink();

使用这个成语的缺点在这里有很好的记录。

链式调用是方法链式的别名。这是众所周知的习语,适用于任何版本的 Java:

class Chained {

    public Chained withFoo() { 
        // ...
        return this;
    }

    public Chained withBar() { 
        // ...
        return this;
    }
}    

JDK 7 的一项提议是允许链接方法也用于 void 返回类型

class ChainedJava7 {

    public void withFoo() { 
        // ...
    }

    public void withBar() { 
        // ...
    }
}    
于 2009-06-18T10:30:15.810 回答
2

可能会让你感兴趣。

于 2009-06-18T10:24:16.040 回答
2

我很喜欢with这种形式的陈述,但我更喜欢它们的 VB 版本:

With testObject
    .Height = 100
    .Text = "Hello, World"
    .ForeColor = System.Drawing.Color.Green
End With

由于With块中的每个属性仍然必须以 a 开头,.因此您知道您引用的是 Object 属性而不是局部变量,从而减少了任何命名空间冲突。

如果我们以您的为例:

with (new DrinkBuilder()) {
    add(“tequila”);
    add(“orange liqueur”);
    add(“lime juice”);
    withRocks();
    withSalt();
    margarita = drink();
}

没有简单的方法来判断withSalt()是本地类的方法DrinkBuilder还是本地类中的方法。如果您只允许块中的with-ed 对象的方法,with那么我认为它们变得不那么有用。

于 2009-06-18T10:33:49.063 回答
1

我不喜欢使用with; 我更喜欢Pythonwith语句。不过,我确实同意你的void看法void。在您提供的示例中,如果一个人真的希望能够链接方法调用,他们应该只更改其方法的返回类型,以便它们是可链接的。

于 2009-06-18T10:23:04.047 回答
1

也许对一个对象的多次调用表明某些代码需要移动?

于 2009-06-18T11:42:16.413 回答
1

Joshua Bloch 在Effective Java Item #2 中强烈建议在您有一个带有很多参数的构造函数时使用 Builder。一个原因是可以编写它来保证构建的对象始终处于一致状态。它还避免了在构建对象的类中具有复杂的“伸缩构造函数”。还有一个问题是,如果您希望构建的对象是不可变的(例如,为了线程安全),它不能有 setter 方法。

于 2009-06-18T12:53:21.683 回答