前言

前一节我们讨论了使用静态工厂方法代替构造器的优点和缺点,这一节我们讨论一下当出现多个构造器参数时我们应该如何处理。静态工厂和构造器有个共同的局限性,它们都不能很好的扩展到大量的可选参数。

不优雅的方法

使用重叠构造器模式

对于这种多个可选参数的类,有些人会使用重叠构造器模式。先提供一个只有必要参数的构造器,第二个构造器有一个可选参数,第三个有两个,以此类推。带来的问题就是构造器的参数太多造成客户端代码难以编写以及难以阅读的问题,虽然IDEA可以帮我们将对应的属性名和参数提示出来,但是太费眼了,很容易出错。比如我们将两个相同类型的参数颠倒了位置,虽然编译器不会报错,但是实际上已经有问题出现了。

使用JavaBeans模式

也就是先调用无参构造器来创建对象,然后调用setter方法来设置每个必要的参数,以及每个相关的可选参数。这也是我平常经常使用的方法,说实话,我觉得这个没啥问题,要不咋处理填充数据的问题呢。但是的确还是会有书中提到的在中途突然报错导致对象创建和我们设想的不一致的问题出现。

优雅的方法

使用Builder方式构建对象


public class Article {
    private Integer articleId;
    private String title;
    private Integer categoryId;
    public static class Builder {
        private String title;
        private Integer categoryId;
        private Integer articleId = Integer.valueOf(0);
        public Builder(String title, Integer categoryId) {
            this.title = title;
            this.categoryId = categoryId;
        }
        public Builder articleId(Integer articleId) {
            this.articleId = articleId;
            return this;
        }
        public Article build(){
            return new Article(this);
        }
    }
    private Article(Builder builder) {
        this.articleId = builder.articleId;
        this.title = builder.title;
        this.categoryId = builder.categoryId;
    }
}

Article article =new Article.Builder("创建和销毁对象-遇到多个构造器参数时要考虑用构造器",15)
                .articleId(0).build();

虽然阅读起来很方便,但是编写builder还是有点麻烦,我们可以直接用Lombok的@Builder注解,直接生成对应的Builder方法。

@Builder(toBuilder = true)
@Getter
public class Author {
    @Builder.Default
    private String userName = "临时营地";
    private String company;
    private Integer age;
    @Singular("addArticle")
    private List<Article> articleList;
}
List<Article> articleList =new ArrayList<>();
        articleList.add(article);
        Author author = Author.builder().userName("临时营地")
        .articleList(articleList)
        .addArticle(article).build();
        author.getArticleList();

@Builder声明实体,表示可以进行Builder方式初始化,@Getter注解,表示只公开getter,对所有属性的setter都封闭,即private修饰

想为属性设置默认值,使用@Builder.Default 注解,

对于实体类中的List 可以添加@Singular注解,注意后面的addArticle,代表我们可以用这个方法来往里面放入单个实体

articleList(articleList)和addArticle(article)都能用

需要注意我们使用Lombok生成的和我们自己写的调用方法还是有区别的。

对象的创建工作提供Builder方法,它提供在设计数据实体时,对外保持private setter,而对属性的赋值采用Builder的方式,这种方式最优雅,也更符合封装的原则,不对外公开属性的写操作!

Builder模式可以对其参数加以约束,build方法可以检验这些约束条件,将参数从builder拷贝到对象中之后,并在对象域而不是builder域中对它们进行检验,如果违反了任何约束,build方法就应该抛出IllegalStateException。Builder模式十分灵活,可以利用单个Builder构建多个对象。唯一的不足在于:为了创建对象必须先创建一个中间对象,builder模式还使得构造的过程更加冗长。

总结

如果类里面有多个可选参数时,设计此种类时Builder模式就是很不错的选择,同时也相较原来的方法可读性更强。


作者:临时营地
链接:https://juejin.cn/post/6995084423876050981
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。