Effective Java 读书笔记:(2) 遇到多个构造器参数时要考虑使用构建器

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

静态工厂和构造器都有个局限性,它们都不能很好地扩展到大量的可选参数.

问题

当一个类中的参数数量变得很多时,如何方便且灵活地创建含有不同参数的实例成了一个复杂的问题.

解决方案

1.普通方法

重叠构造器模式(telescoping constructor),在这种模式下,提供的第一个构造器只包含必要的参数,第二个构造器包含一个可选参数,第三个构造器包含两个可选参数,以此类推.

public class Common {
   static class People {
        private final int id;//必选
        private final String name;//必选
        private final int age; //可选
        private final int grade;//可选
        private final String school;//可选
        public People(int id, String name, int age, int grade, String school) {
            this.id = id;
            this.name = name;
            this.age = age;
            this.grade = grade;
            this.school = school;
        }
        public People(int id, String name, int age, int grade) {
            this(id, name, age, grade, null);
        }
        public People(int id, String name, int age) {
            this(id, name, age, 0);
        }
        public People(int id, String name) {
            this(id, name, 0);
        }
    }
    public static void main(String[] args) {
        People p = new People(12,"网三");
    }
}

当你创建实例的时候,就利用参数列表最短的构造器,但是该列表包含了要设置的所有参数.
缺点:

  • 很明显参数越来越多的情况下,你需要为其设置默认值,并且编写也会变得越来越繁琐
  • 在创建新的实例的时候,你必须了解传入参数表示什么,如果参数变得越来越多, 就会失去控制,同时要保证参数顺序正确.

2. JavaBeans模式

在这种模式下,先声明一个无参构造器来创建对象,然后使用setter方法设置必选参数和可选参数.

public class JavaBeans {
    static class People {
        private  int id = -1;//必选
        private  String name = null;//必选
        private  int age = -1; //可选
        private  int grade = -1;//可选
        private  String school= null;//可选
       public People(){}
        public void setId(int id) {
            this.id = id;
        }
        public void setName(String name) {
            this.name = name;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public void setGrade(int grade) {
            this.grade = grade;
        }
        public void setSchool(String school) {
            this.school = school;
        }
    }
    public static void main(String[] args) {
        People p = new People();
        p.setName("张三");
        p.setId(1);
        //.....
    }
}

缺点:

  • 在构造的过程中,JavaBean可能处于不一致的状态,这里的不一致状态应该指的是如果只提供构造器,不提供setter方法,这样类实例化之后就不能修改了(这种对象可以通过验证构造器参数有效性,来保证一致性),这种可以保证线程安全性,如果提供set方法,就不能保证了.
  • JavaBean模式使得将类做成不可变的可能性不存在.因为要提供setter方法,因而参数不能用final修饰.

3. Builder模式

这种模式既能保证重叠构造器模式的安全性,也能保证像JavaBeans模式一样的可读性.
它不直接生成新的对象,而是先让客户端利用所有必要的参数调用构造器(或者静态工厂),得到一个builder对象.
然后客户端在Build对象上再调用类似于setter的方法,来设置每个可选的参数.最后,客户端调用无参的build方法生成的通常是不可变的对象.
示例:

public class People {
    private final int id;//必选
    private final String name;//必选
    private final int age; //可选
    private final int grade;//可选
    private final String school;//可选

    public static class build {
        private int id = 1;//必选
        private String name = null;//必选
        private int age = 1; //可选
        private int grade = 1;//可选
        private String school = null;//可选

        public build(int id, String name) { this.id = id;this.name = name; }
        public build age(int val) {
            age = val;
            return this;
        }

        public build grade(int val) {
            grade = val;
            return this;
        }

        public build school(String val) {
            school = val;
            return this;
        }
        public  People builer(){
            return  new People(this);
        }

    }

    public People(build build) {
        id = build.id;
        name = build.name;
        school = build.school;
        age = build.age;
        grade = build.grade;
    }

    @Override
    public String toString() {
        return "People{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", grade=" + grade +
                ", school='" + school + '\'' +
                '}';
    }

    public static void main(String[] args) {
        People p = new build(1,"22").age(1).grade(1).builer();
        System.out.println(p.toString());
    }
}

优点:

  • 它可以有多个可变参数,因为build是利用单独的方法设置每一个参数
  • 可以利用单个build创建多个对象.builder参数可以在调用build方法来创建对象期间进行调整,也可以随着不同的对象而改变.
    缺点:
    在某些注重性能的情况下,构建器带来的开销会变得越来越明显.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值