构建者模式不难理解,实现起来也很简单。难点在于使用场景。
它一般适用于业务逻辑比较复杂的类,比如jdbc有很多参数,有一些是必填的,比如host、port、user、password,其他的则是可选参数。
如果按照正常的构造方法,参数可能会爆炸。而采用构造者模式,就会使得这个类的构建变得非常简单。
我们可以把校验逻辑放置到 Builder 类中,先创建建造者,并且通过 set() 方法设置建造者的变量值,
然后在使用 build() 方法真正创建对象之前,做集中的校验,校验通过之后才会创建对象。
同时我们把JDBCConfig的构造方法设为private,不对外暴露set方法,这样就只能使用builder模式创建对象,而且对象还是不可变对象。
/** * JDBC配置类,变量很多 * host、port、user、password、database是必选参数,其他都非必须,有默认值 * 为了避免构造函数参数爆炸,所以使用构建者模式 */ public class JDBCConfig { private String host; private int port; private String user; private String password; private String database; private Boolean useUnicode; private String characterEncoding; private Boolean autoReconnect; private Boolean failOverReadOnly; private int maxReconnects; private int initialTimeout; private int connectTimeout; private int socketTimeout; private JDBCConfig(Builder builder) { this.host = builder.host; this.port = builder.port; this.user = builder.user; this.password = builder.password; this.database = builder.database; this.useUnicode=builder.useUnicode; this.characterEncoding=builder.characterEncoding; this.autoReconnect=builder.autoReconnect; this.failOverReadOnly=builder.failOverReadOnly; this.maxReconnects=builder.maxReconnects; this.initialTimeout=builder.initialTimeout; this.connectTimeout=builder.connectTimeout; this.socketTimeout=builder.socketTimeout; } @Override public String toString() { return "jdbc:mysql://" + host + ":" + port +"/"+database+"?"+ "user=" + user + "&password=" + password + "&useUnicode=" + useUnicode + "&characterEncoding=" + characterEncoding + "&autoReconnect=" + autoReconnect + "&failOverReadOnly=" + failOverReadOnly + "&maxReconnects=" + maxReconnects + "&initialTimeout=" + initialTimeout + "&connectTimeout=" + connectTimeout + "&socketTimeout=" + socketTimeout ; } public static class Builder { private String host; private int port; private String user; private String password; private String database; private boolean useUnicode = true; private String characterEncoding = "gbk"; private Boolean autoReconnect = false; private Boolean failOverReadOnly = false; private int maxReconnects = 3; private int initialTimeout = 1800; private int connectTimeout = 1800; private int socketTimeout = 1800; public JDBCConfig build() { if (StringUtils.isBlank(host)) { throw new IllegalArgumentException("..."); } if(port<0){ throw new IllegalArgumentException("..."); } if (StringUtils.isBlank(user)) { throw new IllegalArgumentException("..."); } if (StringUtils.isBlank(password)) { throw new IllegalArgumentException("..."); } if (StringUtils.isBlank(database)) { throw new IllegalArgumentException("..."); } return new JDBCConfig(this); } public Builder setHost(String host){ if (StringUtils.isBlank(host)) { throw new IllegalArgumentException("..."); } this.host=host; return this; } public Builder setPort(int port){ if(port<0){ throw new IllegalArgumentException("..."); } this.port=port; return this; } public Builder setUser(String user) { if(StringUtils.isBlank(user)){ throw new IllegalArgumentException("..."); } this.user = user; return this; } public Builder setPassword(String password) { if(StringUtils.isBlank(password)){ throw new IllegalArgumentException("..."); } this.password = password; return this; } public Builder setDatabase(String database) { if(StringUtils.isBlank(database)){ throw new IllegalArgumentException("..."); } this.database = database; return this; } public Builder setUseUnicode(boolean useUnicode) { this.useUnicode = useUnicode; return this; } public Builder setCharacterEncoding(String characterEncoding) { this.characterEncoding = characterEncoding; return this; } public Builder setAutoReconnect(Boolean autoReconnect) { this.autoReconnect = autoReconnect; return this; } public Builder setFailOverReadOnly(Boolean failOverReadOnly) { this.failOverReadOnly = failOverReadOnly; return this; } public Builder setMaxReconnects(int maxReconnects) { this.maxReconnects = maxReconnects; return this; } public Builder setInitialTimeout(int initialTimeout) { this.initialTimeout = initialTimeout; return this; } public Builder setConnectTimeout(int connectTimeout) { this.connectTimeout = connectTimeout; return this; } public Builder setSocketTimeout(int socketTimeout) { this.socketTimeout = socketTimeout; return this; } } public static void main(String[] args) { JDBCConfig build = new Builder() .setHost("127.0.0.1") .setPort(8000) .setUser("admin") .setPassword("admin@12345") .setDatabase("fill") .setCharacterEncoding("utf8") .build(); System.out.println(build); } }
输出:
jdbc:mysql://127.0.0.1:8000/fill?user=admin&password=admin@12345&useUnicode=true&characterEncoding=utf8&autoReconnect=false&failOverReadOnly=false&maxReconnects=3&initialTimeout=1800&connectTimeout=1800&socketTimeout=1800