这种语法格式是否适用于Java?

时间:2018-04-17 17:52:55

标签: java syntax

来自Google Protocol Buffers Tutorial

的这段Java代码
Person john =
  Person.newBuilder()
    .setId(1234)
    .setName("John Doe")
    .setEmail("jdoe@example.com")
    .addPhones(
      Person.PhoneNumber.newBuilder()
        .setNumber("555-4321")
        .setType(Person.PhoneType.HOME))
    .build();

自从我用Java编程以来已经有一段时间,但我不熟悉这种形式。我理解Person John = Person.newBuilder(),但.setId.setName等不是newBuilder的参数,也不是彼此之间的终止。也许它只是有趣的缩进。另外,是.setId(1234)隐含的john.setId(1234)?

2 个答案:

答案 0 :(得分:2)

在大多数代码中,这种格式化方式并不完全正常,但是当您使用构建器时,这很常见,因为使用构建器的一部分是能够将调用链接看起来像您发布的内容以便于阅读。

它取代了一个长参数列表,它也往往有奇怪的格式。

这些点表示在前一行上调用方法的返回值(注意,每行以“。”开头的行没有分号)。每个构建器方法都返回“this”,以便以这种方式链接它。

如果一个人对可读性不感兴趣,那么你的例子可以像这样重写:

PersonBuilder johnBuilder = Person.newBuilder();
johnBuilder.setId(1234);
johnBuilder.setName("John Doe");
johnBuilder.setEmail("jdoe@example.com");
PhoneBuilder phoneBuilder = Person.PhoneNumber.newBuilder();
phoneBuilder.setNumber("555-4321");
phoneBuilder.setType(Person.PhoneType.HOME);
johnBuilder.addPhones(phoneBuilder);
Person john = johnBuilder.build();

这种模式是由对“Person”的不可变性的驱使所驱动的 - 不可变的所有参数必须传递给构造函数,使构造函数难以理解。这会将其分解以显示每行传递的内容。 .build()行调用Person构造函数,传入放入构建器的所有值,并返回一个不可变的Person,“john”

根本不使用构建器,它看起来像这样:

Person John = new Person (1234, "John Doe", "jdoe@example.com", new Person.PhoneNumber("555-4321", Person.PhoneType.HOME));

Person John = new Person (
   1234, 
   "John Doe", 
   "jdoe@example.com", 
   new Person.PhoneNumber(
       "555-4321", 
       Person.PhoneType.HOME
   )
);

如果你看一下你的例子,你会发现它比这更具可读性,随着参数列表的增长,它会变得更糟。

答案 1 :(得分:2)

这是一种称为“流畅界面”的模式,通常用于构建器中,以支持您问题中的代码流。

简单的技巧是从setter返回“this”,因此可以直接链接新的方法调用。它与语法无关,在这方面,它只是组织代码的另一种方式。

class Foo {
    public Foo() {}

    public Foo a () { /* do something and */ return this; }
    public Foo b () { /* do something else and */ return this; }
}

new Foo().a().b().a();

这基本上是相同的模式。