最近又看到了Builder构建器模式,想起了之前看的effective java中的讲的创建和销毁对象的方法里面的一章讲到了这个模式,当时不大理解。在网上搜到了好多的博文发现也没有讲清楚真正的设计思想。又看了一遍想了一下,记录下来。
主要不理解的地方就是我印象中的三种对象构建模式之间的区别:构造方法,javaBean模式的get、set方法,Builder模式。
1.构造方法模式
Public class User{
private String name;
private byte sex;
private int age;
private long phone;
public User(String name,byte sex,int age,long phone){
this.name = name;
this.sex = sex;
this.age = age;
this.phone = phone;
}
}
这种是最常用的模式,大家都熟悉。
2.javaBean的get,set方法
Public class User{
private String name;
private byte sex;
private int age;
private long phone;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public byte getSex() {
return sex;
}
public void setSex(byte sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public long getPhone() {
return phone;
}
public void setPhone(long phone) {
this.phone = phone;
}
}
3.Builder构建器模式
public class Contact {
private String name;
private byte sex;
private int age;
private long phone;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public byte getSex() {
return sex;
}
public void setSex(byte sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public long getPhone() {
return phone;
}
public void setPhone(long phone) {
this.phone = phone;
}
public static class Builder {
private String name;
private byte sex;
private int age;
private long phone;
// 构建的步骤
public Builder(String name) {
this.name = name;
}
public Builder age(int val) {
age = val;
return this;
}
public Builder sex(byte val) {
sex = val;
return this;
}
public Builder phone(long val) {
phone = val;
return this;
}
public Contact build() { // 构建,返回一个新对象
return new Contact(this);
}
}
private Contact(Builder b) {
age = b.age;
sex = b.sex;
name = b.name;
phone = b.phone;
}
}
比较:
之前一直不理解Builder构建器为什么要创建内部类来实现。更多的人说可以使创建对象时代码更优美,我觉得把javaBean模式的set方法的返回值修改成当前类本身不是也可以实现么。类似
public class Contact {
private String name;
private byte sex;
private int age;
private long phone;
public String getName() {
return name;
}
public Contact setName(String name) {
this.name = name;
return this;
}
public byte getSex() {
return sex;
}
public Contact setSex(byte sex) {
this.sex = sex;
return this;
}
public int getAge() {
return age;
}
public Contact setAge(int age) {
this.age = age;
return this;
}
public long getPhone() {
return phone;
}
public Contact setPhone(long phone) {
this.phone = phone;
return this;
}
}
这样在构建的时候也可以直接写new Contact().setAge(0).setName("wer").setPhone(213423423423L).setSex((byte) 1);
所以说Builder构建器的真正意义并不是代码优美。
Effective Java中写到:遗憾的是,javaBeans模式自身有着很严重的缺点。因为构造过程被分到了几个调用中,在构建过程中JavaBeans可能处于不一致的状态。类无法仅仅通过检验构造器参数的有效性来保证一致性。试图使用处于不一致状态的对象,将会导致失败,这种失败与包含错误的代码大相径庭,因此它调试起来十分困难。与此相关的另一点不足在于,JavaBeans模式阻止了把类做成不可变得可能,这就需要程序员付出额外的努力来确保它的线程安全。
理解了这段意思之后就可以明白,三种创建对象的方式的区别:
构造方法:可以保证对象不被修改,但是构建不够灵活,对于传不同参数个数时需要多个构造函数。
JavaBeans:构建之后能够灵活的改变对象属性(既是优势也是劣势,需要根据需要来使用),但是赋值过程不是一次性的,也就不是线程安全的。
Builder构建器:既能保证构建时的灵活性,还能保证创建对象的一次性。这就需要一个内部类来存储预设置的属性,在调用bulid()方法的时候一次性构建出来所需要的对象。