2018-10-29 · Develop

Java 中泛型遇上 Builder 模式

在设计模式中对 Builder 模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成。
Java Builder模式主要是用一个内部类去实例化一个对象,避免一个类出现过多构造函数,而且构造函数如果出现默认参数的话,很容易出错。
但是在实际使用中会遇到很有趣的问题,下面就是在 Builder + 泛型的情况下无法进行类型推断的情况。

在描述这个问题之前我们创建几个类来加以说明。

@Getter
@Setter
public class User {

    private String name;

    private Integer age;
}

上面的 User 类就作为泛型需要传递的类型。下面就开始创建泛型 Builder。

public class R<T> {

    private Integer code = 0;

    private String message = "SUCCESS";

    private T data;

    private R(RBuilder<T> builder) {
        this.code = builder.code;
        this.message = builder.message;
        this.data = builder.data;
    }

    public static <T> RBuilder<T> builder() {
        return new RBuilder<>();
    }

    public static class RBuilder<T> {
        private Integer code;
        private String message;
        private T data;

        private RBuilder() {

        }

        public RBuilder<T> code(Integer code) {
            this.code = code;
            return this;
        }

        public RBuilder<T> message(String message) {
            this.message = message;
            return this;
        }

        public RBuilder<T> data(T data) {
            this.data = data;
            return this;
        }

        public R<T> build() {
            return new R<>(this);
        }
    }
}

这是比较常用的返回前端的数据结构,现在的问题是如何去调用这个 Builder 呢。

public class Main {

    public static void main(String[] args) {
        User user = new User();
        
        R<User> r = R.builder().data(user).build(); // 1
        
        R<User> r = R<User>.builder().data(user).build(); // 2
    }
}

上面的两种方式都不能正常的进行调用。
参考这篇文章 Java泛型+Builder模式? 找到了正确的调用方式。
编译器无法独立推断方法的类型参数,则可以通过调用 obj.<Type> method(...)...

R<User> r = R.<User>builder().data(user).build();

后面还有一些折中的用法,但都不是我们的初衷,那样还不如将 RBuilder 的构造函数设置成 public, 再根据情况进行重载。