在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法确相对稳定。如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?这就是要说的builder模式。
今天我想说的是另一个情况下用builder模式,如一个对象有N个成员变量,并且这些成员变量大部分都是可选的,这是不管是用构造函数还是静态工厂方法都是比较难办的,太多的参数会导致在使用这个构造函数或静态工厂方法时,参数是很容易混淆的。有人可能会说用Javabean方式,都用set方法设置,但是使用Javabean构造出的对象不是一个状态一致的对象,有时候需要一些验证什么的,是很难做到的。这是用builder就非常棒的解决了这些问题。我们来看mybatis中的一个例子,再细节的东东,就不说了,直接上源码。
public class ParameterMapping {
private Configuration configuration;
private String property;
private ParameterMode mode;
private Class javaType = Object.class;
private JdbcType jdbcType;
private Integer numericScale;
private TypeHandler typeHandler;
private String resultMapId;
private String jdbcTypeName;
private ParameterMapping() {
}
public static class Builder {
private ParameterMapping parameterMapping = new ParameterMapping();
public Builder(Configuration configuration, String property, TypeHandler typeHandler) {
parameterMapping.configuration = configuration;
parameterMapping.property = property;
parameterMapping.typeHandler = typeHandler;
parameterMapping.mode = ParameterMode.IN;
}
public Builder(Configuration configuration, String property, Class javaType) {
parameterMapping.configuration = configuration;
parameterMapping.property = property;
parameterMapping.javaType = javaType;
parameterMapping.mode = ParameterMode.IN;
}
public Builder mode(ParameterMode mode) {
parameterMapping.mode = mode;
return this;
}
public Builder javaType(Class javaType) {
parameterMapping.javaType = javaType;
return this;
}
public Builder jdbcType(JdbcType jdbcType) {
parameterMapping.jdbcType = jdbcType;
return this;
}
public Builder numericScale(Integer numericScale) {
parameterMapping.numericScale = numericScale;
return this;
}
public Builder resultMapId(String resultMapId) {
parameterMapping.resultMapId = resultMapId;
return this;
}
public Builder typeHandler(TypeHandler typeHandler) {
parameterMapping.typeHandler = typeHandler;
return this;
}
public Builder jdbcTypeName(String jdbcTypeName) {
parameterMapping.jdbcTypeName = jdbcTypeName;
return this;
}
public ParameterMapping build() {
resolveTypeHandler();
return parameterMapping;
}
private void resolveTypeHandler() {
if (parameterMapping.typeHandler == null) {
if (parameterMapping.javaType != null) {
Configuration configuration = parameterMapping.configuration;
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
parameterMapping.typeHandler = typeHandlerRegistry.getTypeHandler(parameterMapping.javaType, parameterMapping.jdbcType);
}
}
}
}
这个例子中还有一个技巧,就是链式方法调用 Builder的 javaType方法都是返回Builder类型的,也就是说可以用 Builder.javaType( JdbcType.CHAR ). javaType(String.class)这样的方式来调用方法,是编码去简单方便。
今天我想说的是另一个情况下用builder模式,如一个对象有N个成员变量,并且这些成员变量大部分都是可选的,这是不管是用构造函数还是静态工厂方法都是比较难办的,太多的参数会导致在使用这个构造函数或静态工厂方法时,参数是很容易混淆的。有人可能会说用Javabean方式,都用set方法设置,但是使用Javabean构造出的对象不是一个状态一致的对象,有时候需要一些验证什么的,是很难做到的。这是用builder就非常棒的解决了这些问题。我们来看mybatis中的一个例子,再细节的东东,就不说了,直接上源码。
public class ParameterMapping {
private Configuration configuration;
private String property;
private ParameterMode mode;
private Class javaType = Object.class;
private JdbcType jdbcType;
private Integer numericScale;
private TypeHandler typeHandler;
private String resultMapId;
private String jdbcTypeName;
private ParameterMapping() {
}
public static class Builder {
private ParameterMapping parameterMapping = new ParameterMapping();
public Builder(Configuration configuration, String property, TypeHandler typeHandler) {
parameterMapping.configuration = configuration;
parameterMapping.property = property;
parameterMapping.typeHandler = typeHandler;
parameterMapping.mode = ParameterMode.IN;
}
public Builder(Configuration configuration, String property, Class javaType) {
parameterMapping.configuration = configuration;
parameterMapping.property = property;
parameterMapping.javaType = javaType;
parameterMapping.mode = ParameterMode.IN;
}
public Builder mode(ParameterMode mode) {
parameterMapping.mode = mode;
return this;
}
public Builder javaType(Class javaType) {
parameterMapping.javaType = javaType;
return this;
}
public Builder jdbcType(JdbcType jdbcType) {
parameterMapping.jdbcType = jdbcType;
return this;
}
public Builder numericScale(Integer numericScale) {
parameterMapping.numericScale = numericScale;
return this;
}
public Builder resultMapId(String resultMapId) {
parameterMapping.resultMapId = resultMapId;
return this;
}
public Builder typeHandler(TypeHandler typeHandler) {
parameterMapping.typeHandler = typeHandler;
return this;
}
public Builder jdbcTypeName(String jdbcTypeName) {
parameterMapping.jdbcTypeName = jdbcTypeName;
return this;
}
public ParameterMapping build() {
resolveTypeHandler();
return parameterMapping;
}
private void resolveTypeHandler() {
if (parameterMapping.typeHandler == null) {
if (parameterMapping.javaType != null) {
Configuration configuration = parameterMapping.configuration;
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
parameterMapping.typeHandler = typeHandlerRegistry.getTypeHandler(parameterMapping.javaType, parameterMapping.jdbcType);
}
}
}
}
这个例子中还有一个技巧,就是链式方法调用 Builder的 javaType方法都是返回Builder类型的,也就是说可以用 Builder.javaType( JdbcType.CHAR ). javaType(String.class)这样的方式来调用方法,是编码去简单方便。