2018-1-18 by Atlas


  • 设计思想

将产品的内部表象和产品的生成过程分割开来,从而使一个建造过程生成具有不同的内部表象的产品对象。建造模式使得产品内部表象可以独立的变化,客户不必知道产品内部组成的细节。建造模式可以强制实行一种分步骤进行的建造过程。

  • 应用场景

需要采取循序渐进组合复杂对象时。

  • UML 类图

Builder UML

  • Builder(建造者)参与者 Builder参与者是规定产生对象实例的接口。包括产生对象实例各个部分的方法和取得最后的结果的方法。
  • ConcreteBuilder(具体建造者)参与者 ConcreteBuilder参与者是实现Builder参与者的接口的类。在实际产生对象实例时所调用的方法就是在这里定义的。
  • Director(监工)参与者 Director参与者利用Builder参与者的接口产生对象实例。设计程序时必须注意不要被ConcreteBuilder参与者牵着鼻子走。为了让ConcreteBuilder参与者无论在什么情形之下都能正常发挥功能,所以只使用Builder参与者的方法。
  • Client(客户)参与者 利用Builder Pattern的参与者。
  • 标准示例

用过elasticsearch java api的小伙伴,自然了解BoolQueryBuilder及其内部doXContext处理的对象都是Builder模式,这里BoolQuerySearchBuilder是我给其上根据业务需要又做的一层封装,也是Builder模式,形式上看就是Builder模式嵌套Builder模式。

public class BoolQuerySearchBuilder extends AbstractSearchBuilder {
    private final BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
    public BoolQuerySearchBuilder mustQueryBuilders(List<QueryBuilder> mustQueryBuilders){
        // 所有分句都必须匹配,类比 SQL 的 AND
        if(mustQueryBuilders != null){
            for(QueryBuilder queryBuilderTmp : mustQueryBuilders){
                boolQueryBuilder.must(queryBuilderTmp);
            }
        }
        return this;
    }
    public BoolQuerySearchBuilder mustNotQueryBuilders(List<QueryBuilder> mustNotQueryBuilders){
        // 所有分句都必须不匹配,类比 SQL 的 NOT
        if(mustNotQueryBuilders != null){
            for(QueryBuilder queryBuilder : mustNotQueryBuilders){
                boolQueryBuilder.mustNot(queryBuilder);
            }
        }
        return this;
    }
    public BoolQuerySearchBuilder shouldQueryBuilders(List<QueryBuilder> shouldQueryBuilders){
        // 至少有一个分句匹配,类比 SQL 的 OR
        if(shouldQueryBuilders != null){
            for(QueryBuilder queryBuilder : shouldQueryBuilders){
                boolQueryBuilder.should(queryBuilder);
            }
        }
        return this;
    }
    @Override
    protected final QueryBuilder queryBuilder() {
        return boolQueryBuilder;
    }
}
  • boolQueryBuilder是复杂的对象。
  • mustQueryBuilders、mustNotQueryBuilder、shouldQueryBuilders分别通过调用boolQueryBuilder的must、mustNot、should循环渐进的组合boolQueryBuilder对象。
  • 循环渐进组合对象过程中返回外层建造者,直到建造者完成对象组合,返回建造的对象。
public class BoolQueryBuilder extends QueryBuilder implements BoostableQueryBuilder<BoolQueryBuilder> {
    private final List<QueryBuilder> mustClauses = new ArrayList<>();
    private final List<QueryBuilder> mustNotClauses = new ArrayList<>();
    private final List<QueryBuilder> shouldClauses = new ArrayList<>();
	public BoolQueryBuilder must(QueryBuilder queryBuilder) {
        mustClauses.add(queryBuilder);
        return this;
    }
	public BoolQueryBuilder mustNot(QueryBuilder queryBuilder) {
        mustNotClauses.add(queryBuilder);
        return this;
    }
	public BoolQueryBuilder should(QueryBuilder queryBuilder) {
        shouldClauses.add(queryBuilder);
        return this;
    }
	protected void doXContent(XContentBuilder builder, Params params) throws IOException {
        builder.startObject("bool");
        doXArrayContent("must", mustClauses, builder, params);
        doXArrayContent("filter", filterClauses, builder, params);
        doXArrayContent("must_not", mustNotClauses, builder, params);
        doXArrayContent("should", shouldClauses, builder, params);
        if (boost != -1) {
            builder.field("boost", boost);
        }
        if (disableCoord != null) {
            builder.field("disable_coord", disableCoord);
        }
        if (minimumShouldMatch != null) {
            builder.field("minimum_should_match", minimumShouldMatch);
        }
        if (adjustPureNegative != null) {
            builder.field("adjust_pure_negative", adjustPureNegative);
        }
        if (queryName != null) {
            builder.field("_name", queryName);
        }
        builder.endObject();
    }
		// ... 
}
  • BoolQueryBuilder对象本身也是Builder模式,循序渐进的组合追加的must、mustNot、should然后最终生成包含逻辑格式的文本Content,整个过程就是elasticsearch根据查询条件动态生成查询命令文本的过程。
  • 调用方具体执行对象建造如下:
public JSONObject search(JSONObject jsonObject) throws Exception {
        logger.info("elasticsearch request json data : [{}]", jsonObject.toString());
        // ...
				// 通过建造者生成查询命令,循序渐进组合对象不仅代码整洁而且过程灵活多变
        SearchBuilder searchBuilder = new BoolQuerySearchBuilder()
                .shouldQueryBuilders(shouldQueryBuilders(jsonObject))
                .mustQueryBuilders(mustQueryBuilders(jsonObject))
                .mustNotQueryBuilders(mustNotQueryBuilders(jsonObject));
				// 根据查询命令执行elasticsearch搜索并响应搜索结果
				Map<String, Object> map = searchBuilder.mutiSearch(indexName, indexType, currentPage, pageSize);
				// ...
        logger.info("elasticsearch response json data : [{}]", data.toJSONString());
        return data;
    }
  • 案例鉴赏
public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence{
		// ...
		@Override
    public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }
    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
		@Override
    public StringBuilder append(CharSequence s, int start, int end) {
        super.append(s, start, end);
        return this;
    }
    @Override
    public StringBuilder append(char[] str) {
        super.append(str);
        return this;
    }
		// ...
		@Override
    public String toString() {
        // 通过循序渐进组合追加的字符数组,创建String对象
        return new String(value, 0, count);
    }
}

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /**
     * 字符数组.
     */
    char[] value;
		// ... 
	public AbstractStringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }
	public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }
	public AbstractStringBuilder append(StringBuffer sb) {
        if (sb == null)
            return appendNull();
        int len = sb.length();
        ensureCapacityInternal(count + len);
        sb.getChars(0, len, value, count);
        count += len;
        return this;
    }
		@Override
    public AbstractStringBuilder append(CharSequence s, int start, int end) {
        if (s == null)
            s = "null";
        if ((start < 0) || (start > end) || (end > s.length()))
            throw new IndexOutOfBoundsException(
                "start " + start + ", end " + end + ", s.length() "
                + s.length());
        int len = end - start;
        ensureCapacityInternal(count + len);
        for (int i = start, j = count; i < end; i++, j++)
            value[j] = s.charAt(i);
        count += len;
        return this;
    }
	public AbstractStringBuilder append(char[] str) {
        int len = str.length;
        ensureCapacityInternal(count + len);
        System.arraycopy(str, 0, value, count, len);
        count += len;
        return this;
    }
	public AbstractStringBuilder append(char c) {
        ensureCapacityInternal(count + 1);
        value[count++] = c;
        return this;
    }
		// ... 
}		

StringBuilder的append方法调用基类AbstractStringBuilder的append方法向value字符数组追加字符,最终通过value字符数组完成String对象的创建。