人生很短,只有几百个月;人生很长,大约有31亿5千3百6十万秒,在保证身体的前提下,多学点东西,驱散自己的无知。。。
科学而完美的解释
将一个复杂对象的创建和显示分离开,使得同样的构建过程可以创建不同的表示。比如一个User类的属性有name、age、address、email、job...等,如果想创建一个User对象,传入全部的属性有点太长了,这时可以使用建造者模式,传入一个参数就只设置对应属性的值。
使用场景列举
如果一个类中有很多属性,为了避免构造函数的参数列表过长,影响代码的可读性和易用性,我们可以通过构造函数配合 set() 方法来解决。但是,如果存在下面情况中的任意一种,我们就要考虑使用建造者模式了。
- 我们把类的必填属性放到构造函数中,强制创建对象的时候就设置。如果必填的属性有很多,把这些必填属性都放到构造函数中设置,那构造函数就又会出现参数列表很长的问题。如果我们把必填属性通过 set() 方法设置,那校验这些必填属性是否已经填写的逻辑就无处安放了。
- 如果类的属性之间有一定的依赖关系或者约束条件,我们继续使用构造函数配合 set() 方法的设计思路,那这些依赖关系或约束条件的校验逻辑就无处安放了。(比如设置了A属性,就必须设置B属性 || A属性值为1时,B属性的值必须为2之类的)
- 如果我们希望创建不可变对象,也就是说,对象在创建好之后,就不能再修改内部的属性值,要实现这个功能,我们就不能在类中暴露 set() 方法。构造函数配合 set() 方法来设置属性值的方式就不适用了。
代码实现
/**
* @author a small asshole
* @version 1.0
* @description 建造者模式
* 在下面的 ConstructorArg 类中,当 isRef 为 true 的时候,
* arg 表示 String 类型的 refBeanId,type 不需要设置;
* 当 isRef 为 false 的时候,arg、type 都需要设置。
* 请根据这个需求,完善 ConstructorArg 类。
* @date in 15:10 2020/2/27
* @since 1.0
*/
public class ConstructorArg {
private boolean isRef;
private Class type;
private Object arg;
public boolean isRef() {
return isRef;
}
public Class getType() {
return type;
}
public Object getArg() {
return arg;
}
private ConstructorArg(Builder builder){
this.arg = builder.arg;
this.type = builder.type;
this.isRef = builder.isRef;
}
public static Builder builder(){
return new Builder();
}
public static class Builder {
private boolean isRef;
private Class type;
private Object arg;
public Builder isRef(boolean isRef) {
this.isRef = isRef;
return this;
}
public Builder type(Class type) {
this.type = type;
return this;
}
public Builder arg(Object arg) {
this.arg = arg;
return this;
}
public ConstructorArg build() {
if (!isRef) {
if (arg == null || type == null) {
throw new IllegalArgumentException("属性设置不正确,请检查设置的属性");
}
}
if(!(arg instanceof String) || "".equalsIgnoreCase((String)arg)){
throw new IllegalArgumentException("属性设置不正确,请检查设置的属性");
}
return new ConstructorArg(this);
}
}
public static void main(String[] args) {
ConstructorArg constructorArg = ConstructorArg.builder()
.isRef(true)
.arg(123)
.type(Resources.class)
.build();
}
}
额外的说明
建造者模式相对而言不是很复杂,很多框架中都使用了建造者模式,比如lombok的@Builder注解之类的,详细的大家可以自行阅读源码。。。
结束语
学习一个技术,最好的方法就是慢慢来,同时,自己动手尝试,忌好高骛远。