Effective Java之多个构造参数考虑用构建器(二)
2017-12-12 13:56
656 查看
静态工厂方法和构造器都有一个共同的特点–>无法扩展到大量的参数。
对于大量的参数类,我们有以下方案:
1.重叠构造器。这个源码中经常可以看到,例如HashMap:
也就是说每个HashMap调用的其实都是含有全部参数的构造器public HashMap(int initialCapacity, float loadFactor)
这种重叠构造器的方法在参数较少的时候,是一种不错的选择,可以参数多了的话呢?
参数顺序容易混淆吧?每个参数的意义容易难看懂吧?冗余的代码写得太多了吧?
于是方案二出现了
2.javaBean模式
就是把这个类声明成javabean,只需要调用他的无参构造方法,set,set,set就好了。
这样就避免了很多重叠构造器的问题
但是问题是,set,set,set的连续使用让javabean的构造过程分开来了,让javabean处于不一致的状态(状态就是javabean的属性集合,相邻两个set方法过后的javabean属性不一样,也就是状态不一致),因此,有些不小心的程序员,在set,set,set方法之间使用了javabean,因此可能会导致错误。
有没有更好的方案呢?
*User*类的构造方法是私有的。也就是说调用者不能直接创建User对象。
*User*类的属性都是不可变的。所有的属性都添加了final修饰符,因此User是不可变的,并且在构造方法中设置了值。并且,对外只提供getters方法。
Builder模式使用了链式调用。可读性更佳。
Builder的内部类构造方法中只接收必传的参数,并且该必传的参数适用了final修饰符,可选参数没有final修饰符,因此可以用此builder修改。
调用builder构建User:
Builder模式好处和优点:
使用Builder模式必然会导致写两遍相关属性的代码和SETTER方法,看起来有点吃力不讨好。
然而需要看到的是,客户端代码的可用性和可读性得到了大大提高。与此同时,构造函数的参数数量明显减少调用起来非常直观。
用Builder的构造函数而不是set方法传递客户需要的属性。这样做的好处在于,对象总是能被一次完整的实例化,这能避免对象不一致状态带来可能的错误。
对于大量的参数类,我们有以下方案:
1.重叠构造器。这个源码中经常可以看到,例如HashMap:
public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); this.loadFactor = loadFactor; this.threshold = tableSizeFor(initialCapacity); } public HashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); } public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; }
也就是说每个HashMap调用的其实都是含有全部参数的构造器public HashMap(int initialCapacity, float loadFactor)
这种重叠构造器的方法在参数较少的时候,是一种不错的选择,可以参数多了的话呢?
参数顺序容易混淆吧?每个参数的意义容易难看懂吧?冗余的代码写得太多了吧?
于是方案二出现了
2.javaBean模式
就是把这个类声明成javabean,只需要调用他的无参构造方法,set,set,set就好了。
这样就避免了很多重叠构造器的问题
但是问题是,set,set,set的连续使用让javabean的构造过程分开来了,让javabean处于不一致的状态(状态就是javabean的属性集合,相邻两个set方法过后的javabean属性不一样,也就是状态不一致),因此,有些不小心的程序员,在set,set,set方法之间使用了javabean,因此可能会导致错误。
有没有更好的方案呢?
3.builder设计模式 以下是一个例子 public class User { private final String firstName; // 必传参数 private final String lastName; // 必传参数 private final int age; // 可选参数 private final String phone; // 可选参数 private final String address; // 可选参数 private User(UserBuilder builder) { this.firstName = builder.firstName; this.lastName = builder.lastName; this.age = builder.age; this.phone = builder.phone; this.address = builder.address; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public int getAge() { return age; } public String getPhone() { return phone; } public String getAddress() { return address; } public static class UserBuilder { private final String firstName; private final String lastName; private int age; private String phone; private String address; public UserBuilder(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public UserBuilder age(int age) { this.age = age; return this; } public UserBuilder phone(String phone) { this.phone = phone; return this; } public UserBuilder address(String address) { this.address = address; return this; } public User build() { return new User(this); } } }
*User*类的构造方法是私有的。也就是说调用者不能直接创建User对象。
*User*类的属性都是不可变的。所有的属性都添加了final修饰符,因此User是不可变的,并且在构造方法中设置了值。并且,对外只提供getters方法。
Builder模式使用了链式调用。可读性更佳。
Builder的内部类构造方法中只接收必传的参数,并且该必传的参数适用了final修饰符,可选参数没有final修饰符,因此可以用此builder修改。
调用builder构建User:
new User.UserBuilder("王", "小二") .age(20) .phone("123456789") .address("亚特兰蒂斯大陆") .build();
Builder模式好处和优点:
使用Builder模式必然会导致写两遍相关属性的代码和SETTER方法,看起来有点吃力不讨好。
然而需要看到的是,客户端代码的可用性和可读性得到了大大提高。与此同时,构造函数的参数数量明显减少调用起来非常直观。
用Builder的构造函数而不是set方法传递客户需要的属性。这样做的好处在于,对象总是能被一次完整的实例化,这能避免对象不一致状态带来可能的错误。
相关文章推荐
- Effective Java 2 -- 遇到多个构造器参数的时候考虑构建器
- Effective-Java学习笔记 遇到多个构造器参数时要考虑用构建器
- 第二条:遇到多个构造参数时要考虑用构建器
- [Effective Java Distilled] Item 2 当构造方法中有多个参数时,考虑建造者模式
- 2、遇到多个构造参数的时候需要考虑使用构建器(effective java)
- [Effective Java Distilled] Item 二 当构造方法中有多个参数时,考虑建造者模式
- [Effective Java Distilled] Item 2 当构造方法中有多个参数时,考虑建造者模式
- Java当遇到多个构造器参数时考虑构建器
- Effective Java 第二条:遇到多个构造器参数时要考虑用构建器
- 学习记录--遇到多个构造参数时考虑用构建器
- Effective JAVA :遇到多个构造器时要考虑使用构建器
- EffectiveJava-2.遇到多个构造器参数时要考虑用构建器
- 多个构造器参数时要考虑用构建器
- eff多可选构造参数可考虑构建器
- 第二条:遇到多个构造器参数时要考虑用构建器
- Java学习笔记2:当构造方法有多个参数时考虑使用Builder
- 《Effective java》读书记录-第2条-遇到多个构造器参数时要考虑用构建器
- 遇到多个构造器参数时考虑使用构建器
- 第2条:遇到多个构造器参数时要考虑用构建器
- Effective Jave——第2条: 遇到多个构造器参数时考虑使用构建器(Builder)