专栏首页撸码那些事Lombok @Builder注解与继承

Lombok @Builder注解与继承

Builder 模式的链式调用写起来很方便,但是自己实现 Builder 模式要在 POJO 类中写较多代码。Lombok 的 @Builder注解可以方便的支持 Builder 模式,但是在继承场景下,会出现 Lombok @Builder注解不会为继承的字段生成代码的问题。

如下面代码所示:

@NoArgsConstructor@AllArgsConstructorpublic class Parent {    private String b;}
@Builder@NoArgsConstructor@AllArgsConstructorpublic class Child extends Parent {    private String b;}

在通过构造模式创建 Child 对象时,不能链式调用 a() 方法。

即使给父类Parent也添加@Builder注解,依然无法调用。

@Builder@NoArgsConstructor@AllArgsConstructorpublic class Parent {    private String b;}

自己实现 Builder 模式

使用 Lombok @Builder注解 可以很方便的使用构造模式, 我们也可以自己实现 Builder 模式,这将有助于我们理解 Builder 模式在继承场景下问题的本质。

自己实现 Builder 模式主要有四个步骤:

  1. 在POJO 类中创建 builder 方法,创建并返回 Builder 对象
  2. 需要创建一个内部静态 Builder 类,并且在 Builder 类中创建和POJO 类中相同的字段
  3. 为每个字段提供 setter 方法,并且返回对象本身,实现链式调用
  4. 在静态 Builder 类创建 build 方法,创建并返回 POJO 对象
public class Parent {    private String b;
    public static Parent.ParentBuilder builder() {        return new Parent.ParentBuilder();    }
    public Parent() {    }
    public Parent(String b) {        this.b = b;    }
    public static class ParentBuilder {        private String b;
        ParentBuilder() {        }
        public Parent.ParentBuilder b(String b) {            this.b = b;            return this;        }
        public Parent build() {            return new Parent(this.b);        }    }}
public class Child extends Parent {    private String b;
    public static Child.ChildBuilder builder() {        return new Child.ChildBuilder();    }
    public Child() {    }
    public Child(String b) {        this.b = b;    }
    public static class ChildBuilder {        private String b;
        ChildBuilder() {        }
        public Child.ChildBuilder b(String b) {            this.b = b;            return this;        }
        public Child build() {            return new Child(this.b);        }    }}

其实上面的代码就是 Lombok @Builder注解在背后为我们做的事情,也解释了为什么 Builder 模式在继承场景下会出现问题。类是继承的,但类中的 builder 类并无继承关系

Builder 模式下的继承关系

那么这个问题就无法解决了吗?如果没有办法解决,Builder 模式的威力将大打折扣。幸运的是,我从网上寻找到了一种解决方式。 原文:

Lombok’s @Builder annotation and inheritance I’ve written about Project Lombok’s @Builder annotation before (see here and here). We’ve started using it in our project some time ago in favour of the code generation library PojoBuilder. One thing has bugged me though during that time: Lombok’s @Builder annotation won’t generate code for inherited fields. It turns out, there is a solution to this problem. We have been using @Builder on the class itself, but you can also put it on a class’s constructor or on a static method. In that case, Lombok will create a setter method on the builder class for every parameter of the constructor/method. That means you can create a custom constructor with parameters for all the fields of the class including its superclass.

@AllArgsConstructorpublic class Parent {   private String a;} public class extends  Parent {    private  String b;   @Builder   private Child(String a, String b){     super (a);     this.b = b;  }}

By setting the visibility of the constructor to private you can make sure that it is only available to Lombok (thanks to Mathias for the tip!). As a result you can then use the generated builder like this:

Child.builder().a("testA").b("testB").build() 

The official documentation explains this, but it doesn’t explicitly point out that you can facilitate it in this way.

我尝试着做了翻译:

我曾经写过有关 Lombok _@Builder _注解的文章。不久前,我们开始在项目中使用到了它。但在此期间,有一件事情困扰着我: Lombok _@Builder _注解不会为继承的字段生成代码。事实证明,这个问题有一个解决方案。

我们通常都是将 _@Builder _注解用于类本身,但是同样可以将其用于类的构造方法或者是静态方法上。如果是这样, Lombok 会在 builder 类中为构造方法或者静态方法的每一个参数创建 setter 方法。这意味着,你可以创建一个自定义的构造方法,其中包含该类(包括其超类)所有字段的参数。

@AllArgsConstructorpublic class Parent {  private String a;}
public class Child extends Parent {  private String b;
  @Builder  private Child(String a, String b){    super(a);    this.b = b;  }}

通过将构造方法的可见性设置成私有的,可以确保其只对 Lombok 可用。因此你可以使用生成的构建器,如下:

Child.builder().a("testA").b("testB").build()

官方文档对其进行了解释,但是并没有明确指出可以通过这种方式提供便利。

参考

Lombok’s @Builder annotation and inheritance

本文分享自微信公众号 - CoderFocus(lumanxs),作者:宋文杰

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-04-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 使用缓存的正确姿势

    缓存是现在系统中必不可少的模块,并且已经成为了高并发高性能架构的一个关键组件。这篇博客我们来分析一下使用缓存的正确姿势。

    撸码那些事
  • 【抽象那些事】不完整的抽象&多方面抽象&未用的抽象&重复的抽象

    撸码那些事
  • 使用缓存的正确姿势

    撸码那些事
  • LintCode 恢复IP地址题目分析

    [ "255.255.11.135", "255.255.111.35" ] (顺序无关紧要)

    desperate633
  • Unity AI 感知侦探

    视觉感知一般会有一个视野范围,这个范围与角色的朝向有关,只有在视觉范围内角色才有可能感知得到,这个范围与一个扇形接近,可以直接用半径和角度来控制。

    汐夜koshio
  • 深度神经网络移动终端GPU加速实践

    我们尝试去工程化深度神经网络并最终落地,当中的一些实践经验通过本文记录下来。

    腾讯Bugly
  • 有趣的 Python 特性 1 | 是谁吃掉了我的外部变量?

    Python 提供了很多让使用者觉得舒服至极的功能特性,但是随着不断的深入学习和使用 Python,我发现其中存在着许多玄学的输出与之前预想的结果大相径庭,这个...

    Rocky0429
  • “智慧工地”是行业发展的必然选择

      智能视频分析技术其本身是一项信息技术,为建筑施工质量安全管理提供了先进技术手段,通过安装在建筑施工作业现场的各类监控装置,构建智能监控和防范体系,有效弥补传...

    倍特威视
  • 学界 | 山东大学提出 PointCNN:让 CNN 更好地处理不规则和无序的点云数据

    机器之心
  • 自动化测试项目基础--视频讲解

    今天开始分享如何写一个自动化测试项目。对于一个长期的自动化测试项目,我的思路如下:现有一个项目的基类,实现对获取请求对象和发送解析请求对象的封装,自定义用户信息...

    FunTester

扫码关注云+社区

领取腾讯云代金券