02 遇到多个构造器参数时要考虑用构建器

静态工厂方法和构造器的共同缺点或者局限性就是:对于存在大量可选参数的类中,其扩展性都不是很好。构建器(Builder)可以比较好的解决这些问题。

重叠构造器
在介绍构建器之前先介绍下重叠构造器吧。什么是重叠的构造器呢?就是有多个构造器,重叠嘛。。。这些构造器有一些特点:至少有一个包含所有必要属性的构造器,必要属性。。。这么说还有非必要属性,是的,重叠构造器应用的一个场景就是,对于一个类来说,它其中的所有属性不一定都是必须要使用或者设置值的,举个栗子来说吧,用户在某个网站上注册的时候,有一些信息比如用户名密码是必须要填的,而有一些信息比如生日住址之类的就是非必须的。
回到正题,除了包含所有属性的构造器之外,还有多个构造器,这些构造器中至少包含必要属性和若干个非必要属性,也可以只包含必要属性哦。这些构造器其实最终都是转到了包含所有属性的构造器,只是那些未包含的非必要属性被设置成默认值了而已。光说不练非好汉,下面就直接来个栗子说明一下吧:

public class Person {
    private String name;//姓名或者用户名->必须
    private String phone;//电话->必须
    private int age;//年龄->可选
    private String address;//地址->可选

    /**
     * 包含所有属性的构造方法
     */
    public Person(String name, String phone, int age, String address) {
        this.name = name;
        this.phone = phone;
        this.age = age;
        this.address = address;
    }

    /**
     * 包含必要属性和一个可选属性的构造方法
     */
    public Person(String name, String phone, int age) {
        this(name, phone, age, "");
    }

    /**
     * 包含必要属性和一个可选属性的构造方法
     */
    public Person(String name, String phone, String address) {
        this(name, phone, 0, address);
    }

    /**
     * 包含必须属性的构造方法
     */
    public Person(String name, String phone) {
        this(name, phone, 0);
//        this(name,phone,"");//当然也可以选择这个构造方法,结果是一样的
    }
}

重叠构造器的问题:
与该方法的特点对应,如果一个类中包含很多的参数,就会写很多的构造方法,而且阅读性不高。还有啊,客户端在调用的时候需要仔细了解各个构造方法的含义,如果不小心把参数的含义看错了,或者位置颠倒了就会产生错误,而且错误还不好定位。。。下面介绍另外一种方法--JavaBean模式。

JavaBean模式
这种模式也很常用,简单来说就是类中存在一个无参的构造方法(哎呀,参考资料中都是构造器,本人比较习惯用构造方法,所以可能一会构造器一会构造方法的,请谅解。。。),然后构造方法就没有别的了,对,就是没有别的了。你可能会问,那类中的参数怎么办呢?别急,类中还存在一大堆set方法,作用就是设置参数。所以,这种方法比较好地弥补了重叠构造器的不足,创建实例的过程:

Person person=new Person();
person.setName("路飞");
person.setAge(18);
//其他的set方法。。。。

同样的,这种方法也存在缺点:并发问题,构造过程中JavaBean可能处于不一致的状态。并且,该方法阻止了把类做成不可变的可能。

前面巴拉巴拉一大堆,目的就是为了引出本文的重头戏:Builder模式。

Builder模式
上代码:

public class PersonB {
    private String name;//姓名或者用户名->必须
    private String phone;//电话->必须
    private int age;//年龄->可选
    private String address;//地址->可选

    /**
     * 包含所有属性的构造方法
     */
    private PersonB(Builder builder) {//通过Builder来构造,该方法是private类型的
        this.name = builder.name;
        this.phone = builder.phone;
        this.age = builder.age;
        this.address = builder.address;
    }

    public static class Builder {
        private String name;//姓名或者用户名->必须
        private String phone;//电话->必须

        //设置了默认值
        private int age = 0;//年龄->可选
        private String address = "";//地址->可选

        public Builder(String name, String phone) {
            this.name = name;
            this.phone = phone;
        }

        public Builder age(int age) {
            this.age = age;
            return this;
        }

        public Builder address(String address) {
            this.address = address;
            return this;
        }

        public PersonB build() {
            return new PersonB(this);
        }
    }

}

注意:PersonB这个类的构造方法是private类型的,也就是说无法通过new PersonB()来创建实例。具体怎么用呢,来来来,敲黑板啦~

PersonB person = new PersonB.Builder("山治", "110").age(20).address("桑尼号").build();

是不是很简单,而且也很明了,传递了必要的参数和非必须的参数。同时在build()方法中可以对参数进行检验(你需要根据实际情况添加对应的检验逻辑)。
在抽象工厂中的应用:
客户端可以将builder传递给某个方法,这样该方法就能够创建一个或者多个对象了。如果可以使用泛型的话:

public interface Builder<T> {
  public T build();
}

Tree buildeTree(Builder<? extends Node> nodeBuilder) { ... }

代码中第二部分就是一个实际的应用,功能就是通过Builder来创建一棵树。。。

下面说下该方法的缺点吧:
一般来说一个方法的缺点往往与其实现方法相关,Builder模式的缺点就是,必须要先创建它的构建器Builder(这不是废话吗)。该方法可能更加冗长,比较适合参数多的情况,比如有4个或者更多的参数。

总之:如果类的构造器或者静态工厂中有多个参数,在设计这种类的时候,可以考虑Builder模式,当一个类中大多数参数都是可选的时候就更完美了~。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容