学习effective java-2创建和销毁对象之当类有多个构造参数时,请考虑使用一个builder来创建对象

该知识点是自己从书籍中学习的笔记。

背景:
       当类的构造方法有很多参数(超过3个)或者参数类型基本是一样时,这时使用静态工程方法或者构造方法来创建对象,并不合适,因为客户在使用该类创建对象时,必须清楚每个参数代表的意义,稍不注意就会将参数值写错或者参数不够。
以下例子都是以Student类为基础,该类的必须成员属性:id(学生编号),name(姓名);可选成员属性:address,telephone,remark。
定义:
    不直接创建带必须参数的对象,而是通过调用该类的一个内部静态成员Builder类(该类的构造方法含有所有必须参数(或者静态工程方法))得到一个builder对象。用户使用这个builder对象来设置对象各个可选的参数值,最后用户调用该builder对象的一个无参数的方法来获取的一个不变的Student对象。
关于背景中的问题处理方法:
  1.采用“telescoping constructor pattern”(伸缩构造函数模式),即在编写多个构造方法,这些构造方法都必须填写上必要的参数,然后每个构造方法再添加不同的可选参数。例如:
// Telescoping constructor pattern - does not scale well!
public class Student {
 private final String id;
 private final String name;
 private final int age;
 private final String address;

 public Student(String id, String name) {
  this(id, name, 0, null);
 }

 public Student(String id, String name, int age) {
  this(id, name, age, null);
 }

 public Student(String id, String name, String address) {
  this(id, name, 0, address);
 }

 public Student(String id, String name, int age, String address) {
  this.id = id;
  this.name = name;
  this.address = address;
  this.age = age;
 }
}
调用的时候,就如下:Student  student = new Student (“12”, “san”,  10, “add”);
明显这种方式不太妥当,当有多个可选属性或者可选属性组合的时候,就特别不适合。
2.采用JavaBean的设计模式,先建立对象,然后再通过setter/getter的方式来设置值。如下:
public class Student1 {
 private String id;
 private String name;
 private int age;

 public String getId() {
  return id;
 }

 public void setId(String id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public int getAge() {
  return age;
 }

 public void setAge(int age) {
  this.age = age;
 }

 public String getAddress() {
  return address;
 }

 public void setAddress(String address) {
  this.address = address;
 }

 private String address;
}
当你调用的时候,如下:
Student1 s = new Student1();
s.setId(“1”);
……
使用用这种方式虽然可以解决方法一的问题,但是会导致创建的对象前后状态或数据信息不一致,因此你必须加强对象的安全管理,因为可以在该对象后面再设置状态或者数据信息。虽然可以使用当参数设置完全,并且在使用之前时,可以将该对象给冻结的方式来解决问题,但是这种方式在实际不适用。
3. 综合了上述两种方式各自的优点,称作“Builder pattern”来解决以上的两种方式的不足。实现过程:不直接创建带必须参数的Student对象,而是用户调用一个含有所有必须参数的构造方法(或者静态工程方法),得到一个builder对象。用户使用这个builder对象来设置Student各个可选的参数值,最后用户调用builer的一个无参数的方法来获取的一个不变的Student对象。在Student类中,builders是一个static member class。如下:
public class Student3 {
private final String id;
private final String name;
private final int age;
private final String address;

public static class Builder {
private final String id;
private final String name;
private int age;
private String address;

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

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

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

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

public Student3(Builder builder) {
this.id = builder.id;
this.name = builder.name;
this.age = builder.age;
this.address = builder.address;
}
public static void main(String[] args) {
Student3 s = new Student3.Builder("1", "1").age(12).address("aaa").build();
}
}
优点:
1. 弥补了方法一、二的缺点;
2. Builder可以检查到属性的必须性和可选性;
3. Builder创建的可选性的属性都是一个方法,不重复;
4. 从jdk1.5开始可以使用泛型的方式来创建Builer,如:
// A builder for objects of type T
public interface Builder<T> {
public T build();
}
缺点:
1. 创建对象之前,必须要创建该对象的builder,这个对性能有些影响。
2. 在可选参数较多的时候,可以使用Builder模式。
适用场景:
当构造参数多,尤其是可选参数多时,可以优先考虑使用Builder模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值