通用Builder工具类

假设有一个Java实体类定义:

public class Request {
    private String type;
    private String op;
    private PageInfo pageInfo;

    public static class PageInfo {
        private Integer pageNum;
        private Integer pageSize;
    }

    // 省略getter和setter...
}

在代码中创建这个对象,需要写以下代码:

public static void main(String[] args) {
    // 创建PageInfo
    Request.PageInfo pageInfo = new Request.PageInfo();
    pageInfo.setPageNum(1);
    pageInfo.setPageSize(10);

    // 创建Request
    Request request = new Request();
    request.setOp("op");
    request.setType("type");
    request.setPageInfo(pageInfo);

    // 使用request...
}

由于对象创建与对象初始化相互分离,以上代码看起来十分冗长,每个属性都需要一条setter语句来赋值,当属性数量较多时看起来非常不优雅。另外,由于嵌套类的存在,创建最外层对象之前,必须把所有内层对象先创建完毕,实在是恶心至极。

针对以上问题,熟悉设计模式的朋友应该很快就能想到使用Builder模式改写这个类:

public class Request {
    private String type;
    private String op;
    private PageInfo pageInfo;

    private Request(String type, String op, PageInfo pageInfo) {
        this.type = type;
        this.op = op;
        this.pageInfo = pageInfo;
    }

    // 省略getter和setter...

    public static RequestBuilder builder() {
        return new RequestBuilder();
    }

    public static class PageInfo {
        private Integer pageNum;
        private Integer pageSize;

        private PageInfo(Integer pageNum, Integer pageSize) {
            this.pageNum = pageNum;
            this.pageSize = pageSize;
        }

        // 省略getter和setter...

        public static PageInfoBuilder builder() {
            return new PageInfoBuilder();
        }

        public static class PageInfoBuilder {
            private Integer pageNum;
            private Integer pageSize;

            public PageInfoBuilder pageNum(Integer pageNum) {
                this.pageNum = pageNum;
                return this;
            }

            public PageInfoBuilder pageSize(Integer pageSize) {
                this.pageSize = pageSize;
                return this;
            }

            public PageInfo build() {
                return new PageInfo(this.pageNum, this.pageSize);
            }
        }
    }

    public static class RequestBuilder {
        private String type;
        private String op;
        private PageInfo pageInfo;

        public RequestBuilder type(String type) {
            this.type = type;
            return this;
        }

        public RequestBuilder op(String op) {
            this.op = op;
            return this;
        }

        public RequestBuilder pageInfo(PageInfo pageInfo) {
            this.pageInfo = pageInfo;
            return this;
        }

        public Request build() {
            return new Request(this.type, this.op, this.pageInfo);
        }
    }
}

这样就能使用流畅的链式调用创建对象,看起来行云流水:

public static void main(String[] args) {
    Request request = Request.builder()
        .op("op")
        .type("type")
        .pageInfo(Request.PageInfo.builder()
            .pageNum(1)
            .pageSize(10)
            .build())
        .build();

    // 使用request...
}

但是问题来了,假设Request这个对象是一个第三方框架或类库中的类,且并没有按照Builder模式来实现,由于无法修改该类的代码,我们也只能被迫使用setter方法来创建这个对象。在这种情况下,我们还能拥有像之前一样丝滑般的体验吗?

下面介绍一个简单的小技巧解决这个问题。

通用Builder工具类

public class BuilderUtils {
    public static <T> T build(T obj, Consumer<T> applyFunc) {
        applyFunc.accept(obj);
        return obj;
    }
}

上面的工具类有一个build方法,这个方法只是在一个指定的对象obj上调用了我们传入的一个任意操作函数applyFunc。有了这个方法,就能在任意对象上实现类似Builder模式的写法。

import static byx.test.BuilderUtils.build;

public static void main(String[] args) {
    Request request = build(new Request(), r -> {
        r.setOp("op");
        r.setType("type");
        r.setPageInfo(build(new Request.PageInfo(), p -> {
            p.setPageNum(1);
            p.setPageSize(10);
        }));
    });

    // 使用request...
}

这个方法巧妙地将对象创建与对象初始化结合在了一起。实际上这种方法比Builder模式更灵活,因为build方法传入的lambda表达式中可以执行任意操作,而不仅仅是给对象属性赋值。我们可以在其中加入任意复杂的逻辑,比如根据某些条件为对象属性赋予不同的值,或者执行初始化逻辑等。更重要的是,所有操作都包含在一个语句中,而不会打散在数不清的setter调用中。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

byx2000

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值