原文:原文链接

1。概述

Lombok库提供了一种无需编写任何样板代码即可实现* Builder Pattern的好方法: [@Builder](https:// projectlombok.org/features/Builder)*注释。

在这个简短的教程中,我们将专门学习涉及继承时如何处理@ Builder注释。我们将演示两种技术。一种依赖于标准的Lombok功能。另一个则利用了Lombok 1.18中引入的实验功能。

有关Builder注释的更广泛概述,请参考使用Lombok的@ Builder注释。

Project Lombok简介中也提供了有关Project Lombok库的详细信息。

2。@ Builder*和继承

2.1。定义问题

假设我们的Child类扩展了Parent类:

@Getter
@AllArgsConstructor
public class Parent {
    private final String parentName;
    private final int parentAge;
}

@Getter
@Builder
public class Child extends Parent {
    private final String childName;
    private final int childAge;
}

在扩展了此类的另一个类上使用@ Builder时,我们将在注释上收到以下编译错误:

隐式超级构造函数Parent()未定义。必须显式调用另一个构造函数

这是由于Lombok不考虑超类的字段,而仅考虑了当前类的字段。

2.2。解决问题

对我们来说幸运的是,有一个简单的解决方法。我们可以(使用我们的IDE甚至手动生成)基于字段的构造函数。这也包括超类的字段。我们用@ Builder而不是类来注释它:

@Getter
@AllArgsConstructor
public class Parent {
    private final String parentName;
    private final int parentAge;
}

@Getter
public class Child extends Parent {
    private final String childName;
    private final int childAge;

    @Builder
    public Child(String parentName, int parentAge, String childName, int childAge) {
        super(parentName, parentAge);
        this.childName = childName;
        this.childAge = childAge;
    }
}

这样,我们将能够从Child类访问便捷的构建器,这将使我们也可以指定Parent类的字段:

Child child = Child.builder()
  .parentName("Andrea")
  .parentAge(38)
  .childName("Emma")
  .childAge(6)
  .build();

assertThat(child.getParentName()).isEqualTo("Andrea");
assertThat(child.getParentAge()).isEqualTo(38);
assertThat(child.getChildName()).isEqualTo("Emma");
assertThat(child.getChildAge()).isEqualTo(6);

2.3。使多个* @ Builder* s共存

如果超类本身使用@ Builder进行注释,则在注释Child类的构造函数时会出现以下错误:

返回类型与Parent.builder()不兼容

这是因为Child类正试图公开两个具有相同名称的Builders。

我们可以通过为至少一个构建器方法分配唯一的名称来解决此问题:

@Getter
public class Child extends Parent {
    private final String childName;
    private final int childAge;
    
    @Builder(builderMethodName = "childBuilder")
    public Child(String parentName, int parentAge, String childName, int childAge) {
        super(parentName, parentAge);
        this.childName = childName;
        this.childAge = childAge;
    }
}

然后,我们将能够通过Child.builder()获得 ParentBuilder,并通过Child.childBuilder()获得 ChildBuilder

2.4. 支持更大的继承层次结构

在某些情况下,我们可能需要支持更深的继承层次结构。我们可以使用与以前相同的模式。让我们创建Child的子类。

@Getter
public class Student extends Child {

    private final String schoolName;

    @Builder(builderMethodName = "studentBuilder")
    public Student(String parentName, int parentAge, String childName, int childAge, String schoolName) {
        super(parentName, parentAge, childName, childAge);
        this.schoolName = schoolName;
    }
}

和以前一样,我们需要手动添加一个构造函数。这需要接受所有父类和子类的所有属性作为参数。然后,像以前一样添加@ Builder批注。通过在注释中提供另一个唯一的方法名称,我们可以获得Parent,Child或Student的构建器。

Student student = Student.studentBuilder()
  .parentName("Andrea")
  .parentAge(38)
  .childName("Emma")
  .childAge(6)
  .schoolName("Baeldung High School")
  .build();

assertThat(student.getChildName()).isEqualTo("Emma");
assertThat(student.getChildAge()).isEqualTo(6);
assertThat(student.getParentName()).isEqualTo("Andrea");
assertThat(student.getParentAge()).isEqualTo(38);
assertThat(student.getSchoolName()).isEqualTo("Baeldung High School");

然后,我们可以扩展此模式以处理任何继承深度。我们需要创建的构造函数可能会变得很大,但是您的IDE可以帮助您。

3。 @ SuperBuilder*和继承

如我们前面所述,Lombok的1.18版引入了* @ SuperBuilder*批注。我们可以使用它来以更简单的方式解决问题。

3.1. 应用注释

我们可以使建造者能够看到其祖先的属性。

为此,我们使用@ SuperBuilder批注对我们的类及其祖先进行批注。

让我们在这里演示我们的三层层次结构。请注意,简单父级和子级继承的原理是相同的:

@Getter
@SuperBuilder
public class Parent {
    // same as before...

@Getter
@SuperBuilder
public class Child extends Parent {
   // same as before...

@Getter
@SuperBuilder
public class Student extends Child {
   // same as before...

当所有类都以这种方式注释后,我们将为子类获得一个构建器,该构建器也公开了父级的属性。

注意,我们必须注释所有类。 @ SuperBuilder不能在同一类层次结构中与@ Builder混合。这样做会导致编译错误。

3.2. 使用构建器

这一次,我们不需要定义任何特殊的构造函数。由@ SuperBuilder生成的生成器类的行为就像我们使用主Lombok @ Builder生成的生成器类一样:

Student student = Student.builder()
  .parentName("Andrea")
  .parentAge(38)
  .childName("Emma")
  .childAge(6)
  .schoolName("Baeldung High School")
  .build();

assertThat(student.getChildName()).isEqualTo("Emma");
assertThat(student.getChildAge()).isEqualTo(6);
assertThat(student.getParentName()).isEqualTo("Andrea");
assertThat(student.getParentAge()).isEqualTo(38);
assertThat(student.getSchoolName()).isEqualTo("Baeldung High School");

4。结论

我们已经看到了如何处理在利用继承的类中使用@ Builder注释的常见陷阱。

如果使用主要的Lombok @ Builder批注,我们还有一些额外的步骤可以使它起作用。但是,如果我们愿意使用实验性功能,那么@ SuperBuilder可以简化事情。

和往常一样,完整的源代码可在[GitHub上]获得(https://github.com/eugenp/tutorials/tree/master/lombok)。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐