【问题标题】:Can I use the Lombok @Builder passing the parent class as parameter?我可以使用 Lombok @Builder 传递父类作为参数吗?
【发布时间】:2021-03-24 14:34:42
【问题描述】:

我想创建一个新的Child 实例,传递Parent 和其他附加参数。

例如,如果我有:

public class Parent {
    public String param1;
    public String param2;
    // many parameters
    public String paramN;
}

public class Child extends Parent {
    public String subValue;
}

对于 lombok,是否有一个构建器可以让我创建一个 Child 实例,并将 Parent 和缺失值作为参数传递?

如果我能写这样的东西会更容易:

Parent p = Parent.builder()
                 .param1("a")
                 .param2("b")
                 // many parameters
                 .paramN("b")
                 .build();
Child c = Child.builder(p).subValue("c").build();

【问题讨论】:

  • 你为什么不喜欢一次性创建孩子的选项,比如 Child c = Child.builder()..name("a").value("b").subValue(" c").build();在@SuperBuilder 的帮助下
  • @ShaileshChandra 好吧,在实际情况下,父母确实有很多字段。这样就不容易了……
  • 明白了,那么我建议去组合而不是继承,你怎么看,你可以有一个以 parent 类型命名的字段
  • @ShaileshChandra 作品不是我想要的:)
  • 好的,但是如果我们谈论 lombok 它只在编译期间生成代码,想想如果 lombok 决定提供这个它将生成什么代码?

标签: java lombok


【解决方案1】:

其他答案并不能真正让您的客户端代码简单地重用您已有的父实例。但这是可行的。你有两个选择:

最难的是编写您想要的自定义注释。您甚至可以使其通用,以便它适用于具有父/子层次结构的任何类。看看这个example。如果你觉得勇敢,可以在 Lombok's github 页面上提出功能请求。

选项二是为孩子编写自定义构建器。见example here。在初始化步骤中的自定义构建器中,您将读取传入的 Parent 实例,并仅设置继承的字段。

【讨论】:

  • 谢谢,很有趣。即使我对此表示赞同,选项二也指向一个有很多答案的问题,目前尚不清楚您所指的示例是什么答案。你能说得更具体点吗?
【解决方案2】:

常规的@Builder 在这里是不够的,因为您正在处理一个类层次结构。但是,@SuperBuilder 正是针对这种情况而制作的。

@SuperBuilder 生成加载了泛型的复杂代码。如果不深入了解 @SuperBuilder 生成的代码,这使得该解决方案难以理解。你应该考虑一下这是否值得。

这是解决方案(Lombok >= 1.18.16):

@SuperBuilder(toBuilder = true)
public static class Parent {
    public String param1;
    public String param2;
    // many parameters
    public String paramN;

    public abstract static class ParentBuilder<C extends Parent, B extends Parent.ParentBuilder<C, B>> {
        protected B $fillValuesFromParent(Parent instance) {
            $fillValuesFromInstanceIntoBuilder(instance, this);
            return self();
        }
    }
}

@SuperBuilder(toBuilder = true)
public static class Child extends Parent {
    public String subValue;

    public static ChildBuilder<?, ?> toBuilder(Parent p) {
        return new ChildBuilderImpl().$fillValuesFromParent(p);
    }
}

Child 上的新toBuilder 方法会创建一个新的ChildBuilderImpl(调用build() 时将创建一个Child 实例)。为了填充给定Parent p 中的值,它从ParentBuilder 调用新的$fillValuesFromParent 方法。此方法进一步将调用委托给由 Lombok 生成的方法 $fillValuesFromInstanceIntoBuilder,并将字段值实际复制到新的构建器实例。

还要注意方法上的$ 前缀。这基本上是说:我是一个实现细节;除非您知道自己在做什么,否则不要使用我,我可能会在下一个 Lombok 版本上中断,恕不另行通知。

【讨论】:

    【解决方案3】:

    我建议你使用@SuperBuilder

    @SuperBuilder 在 lombok v1.18.2 中作为实验性功能引入。 @SuperBuilder 注释为您的 类。与@Builder 相比,@SuperBuilder 也适用于字段 来自超类。但是,它仅适用于类型。最重要的是, 它要求所有超类也有 @SuperBuilder 注释。

    @Getter
    @SuperBuilder
    public class Parent {
        public String name;
        public String value;
    }
    
    @Getter
    @SuperBuilder
    public class Child extends Parent {
        public String subValue;
    }
    

    那么你需要做的就是

    Child.builder().name("a").value("b").subValue("c").build();
    

    【讨论】:

    • 这并不完全符合 OP 的要求......
    • @EvdzhanMustafa 同意,到目前为止,我不认为 Lombok 提供了 OP 想要的东西,或者我可能不知道所以提出了另一种可能性,以便其他寻求答案的人可以了解解决方案
    猜你喜欢
    • 2015-12-29
    • 1970-01-01
    • 2018-10-11
    • 1970-01-01
    • 2013-09-12
    • 1970-01-01
    • 2016-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多