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