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

来源:互联网 发布:高新区行知小学官网 编辑:程序博客网 时间:2024/06/07 07:00

静态工厂方法和构造器的共同缺点或者局限性就是:对于存在大量可选参数的类中,其扩展性都不是很好。构建器(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模式,当一个类中大多数参数都是可选的时候就更完美了~。

阅读全文
1 0
原创粉丝点击