定义
建造者模式封装一个产品的构造过程,并允许按步骤构造。
角色
- 抽象建造者(Builder):用于规范产品的各个组成部分,并进行抽象,一般独立于应用程序的逻辑。
- 具体建造者(Concrete Builder):实现抽象建造者中定义的所有方法,并且返回一个组建好的产品实例。
- 产品(Product):建造者模式中的复杂对象,一个系统中会有多于一个的产品类,这些产品类并不一定有共同的接口,完全可以是不相关联的。
- 导演者(Director):负责安排已有模块的顺序,然后告诉Builder开始建造。
类图
优缺点
优点
- 使用建造者模式可以使客户端不必知道产品内部组成的细节
- 具体的建造者类之间是相互独立的,这有利于系统的扩展
- 具体的建造者相互独立,因此可以对建造的过程逐步细化,而不会对其他模块产生任何影响
缺点
- 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制
- 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大
适用场景
- 需要生成的对象具有复杂的内部结构
- 需要生成的对象内部属性本身相互依赖
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
|
public class ProductBuilder { private Product product;
public ProductBuilder() { this.product = new Product(); }
public Product buildPartA(String partA) { product.setPartA(partA); return this.product; }
public Product buildPartB(String partB) { product.setPartB(partB); return this.product; }
public Product buildPartC(String partC) { product.setPartC(partC); return this.product; }
public Product build() { return this.product; } }
public class ProductBuilder { private Product product;
public ProductBuilder() { this.product = new Product(); }
public ProductBuilder buildPartA(String partA) { product.setPartA(partA); return this; }
public ProductBuilder buildPartB(String partB) { product.setPartB(partB); return this; }
public ProductBuilder buildPartC(String partC) { product.setPartC(partC); return this; }
public Product build() { return this.product; } }
|
模式应用
Spring Data ElasticSearch中大量使用了建造者模式,以IndexQueryBuilder
为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| public class IndexQueryBuilder { private String id; private Object object; private Long version; private String indexName; private String type; private String source; private String parentId;
public IndexQueryBuilder() { }
public IndexQueryBuilder withId(String id) { this.id = id; return this; }
public IndexQueryBuilder withObject(Object object) { this.object = object; return this; }
public IndexQueryBuilder withVersion(Long version) { this.version = version; return this; }
public IndexQueryBuilder withIndexName(String indexName) { this.indexName = indexName; return this; }
public IndexQueryBuilder withType(String type) { this.type = type; return this; }
public IndexQueryBuilder withSource(String source) { this.source = source; return this; }
public IndexQueryBuilder withParentId(String parentId) { this.parentId = parentId; return this; }
public IndexQuery build() { IndexQuery indexQuery = new IndexQuery(); indexQuery.setId(this.id); indexQuery.setIndexName(this.indexName); indexQuery.setType(this.type); indexQuery.setObject(this.object); indexQuery.setParentId(this.parentId); indexQuery.setSource(this.source); indexQuery.setVersion(this.version); return indexQuery; } }
|
实际应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
| public class ExportDefinition { /** * 每张表最多只能存储1048576行数据 */ public static final int MAX_ROW = 1048576;
/** * 表名 */ private String sheetName;
/** * 标题定义 */ private TitleDefinition title;
/** * label定义列表 */ private List<LabelDefinition> labels;
/** * 属性定义列表 */ private List<PropertyDefinition> properties;
/** * 子定义列表(适用于子表) */ private List<ExportDefinition> childrenDefinitions;
/** * 主题函数工厂(函数接受一个Workbook并返回一个CellStyle) */ private StyleFunctionFactory styleFunctionFactory;
/** * 内存中数据量达到多少时刷新 */ private int windowSize;
/** * 是否压缩临时excel */ private boolean compress;
/** * 打包导出时,每个excel的最大存储数据量 */ private int packageSize;
private ExportDefinition(Builder builder) { this.sheetName = builder.sheetName; this.title = builder.title; this.labels = builder.labels; this.properties = builder.properties; this.childrenDefinitions = builder.childrenDefinitions; this.styleFunctionFactory = builder.styleFunctionFactory; this.windowSize = builder.windowSize; this.compress = builder.compress; this.packageSize = builder.packageSize;
if (this.title != null) { this.title.setWidth(this.properties.size()); } }
public String getSheetName() { return sheetName; }
public TitleDefinition getTitle() { return title; }
public List<LabelDefinition> getLabels() { return labels; }
public List<PropertyDefinition> getProperties() { return properties; }
public List<ExportDefinition> getChildrenDefinitions() { return childrenDefinitions; }
public StyleFunctionFactory getStyleFunctionFactory() { return styleFunctionFactory; }
public int getWindowSize() { return windowSize; }
public boolean isCompress() { return compress; }
public int getPackageSize() { return packageSize; }
/** * 返回表头高度 */ public int getHeaderHeight() { return labels.stream().map(LabelDefinition::getHeight).max(Integer::compareTo).orElse(0); }
/** * 返回表头宽度 */ public int getHeaderWidth() { return labels.stream().map(LabelDefinition::getWidth).max(Integer::compareTo).orElse(0); }
/** * 返回表头起始行索引 */ public int getHeaderBeginRowIndex() { return getTitle() == null ? 0 : getTitle().getHeight() + 1; }
/** * 返回数据起始行索引 */ public int getDataBeginRowIndex() { return getHeaderBeginRowIndex() + getHeaderHeight(); }
/** * 构造器 */ public static class Builder { private String sheetName;
private TitleDefinition title;
private List<LabelDefinition> labels;
private List<PropertyDefinition> properties;
private List<ExportDefinition> childrenDefinitions;
/** * 没有定义主题函数工厂,就使用默认的 */ private StyleFunctionFactory styleFunctionFactory = new DefaultStyleFunctionFactory();
/** * 内存中数据量达到100就刷新 */ private int windowSize = SXSSFWorkbook.DEFAULT_WINDOW_SIZE;
/** * 默认不压缩临时excel */ private boolean compress;
/** * 打包导出时,默认每个excel的最大存储数据量为200000 */ private int packageSize = 200000;
public Builder sheetName(String sheetName) { this.sheetName = sheetName; return this; }
public Builder title(TitleDefinition title) { this.title = title; return this; }
public Builder labels(List<LabelDefinition> labels) { this.labels = labels; return this; }
public Builder properties(List<PropertyDefinition> properties) { this.properties = properties; return this; }
public Builder childrenDefinitions(List<ExportDefinition> childrenDefinitions) { this.childrenDefinitions = childrenDefinitions; return this; }
public Builder styleFunctionFactory(StyleFunctionFactory functionFactory) { this.styleFunctionFactory = functionFactory; return this; }
public Builder windowSize(int windowSize) { this.windowSize = windowSize; return this; }
public Builder compress(boolean compress) { this.compress = compress; return this; }
public Builder packageSize(int packageSize) { this.packageSize = packageSize; return this; }
public Builder simpleTitle(String title) { this.title = new TitleDefinition.Builder().name(title).height(1).build(); return this; }
public Builder simpleLabels(List<String> labels) { this.labels = labels.stream() .map(label -> new LabelDefinition.Builder().name(label).build()) .collect(Collectors.toList()); return this; }
public Builder simpleProperties(List<String> properties) { this.properties = properties.stream() .map(property -> new PropertyDefinition.Builder().name(property).build()) .collect(Collectors.toList()); return this; }
public ExportDefinition build() { if (!CollectionUtils.isEmpty(this.properties) && !CollectionUtils.isEmpty(this.labels) && this.properties.size() != this.labels.stream() .map(LabelDefinition::getWidth) .reduce((pre, cur) -> pre + cur) .orElse(0)) { throw new ExportException("labels属性与properties属性未一一对应"); } return new ExportDefinition(this); } } }
|