设计模式之建造者模式
定义
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
结构
- Product,被构建的复杂产品,一般包含多个部件。
- Builder,建造者接口,定义了构建复杂对象的多个部件的方法。
- ProductBuilder,具体建造者,实现了建造者接口。
- Director,指挥者,负责安排复杂对象的构建顺序。
简单实现
具体产品,包含3个部件
public class Product {
private String partA;
private String partB;
private String partC;
public void setPartA(String partA) {
this.partA = partA;
}
public void setPartB(String partB) {
this.partB = partB;
}
public void setPartC(String partC) {
this.partC = partC;
}
public void show() {
System.out.println("partA: " + partA + ",partB: " + partB + ",partC: " + partC);
}
}
建造者接口
/**
* 建造者接口
*/
public interface Builder {
void buildPartA(String partA);
void buildPartB(String partB);
void buildPartC(String partC);
Product getResult();
}
具体建造者
/**
* 具体建造者
*/
public class ProductBuilder implements Builder {
private Product product = new Product();
@Override
public void buildPartA(String partA) {
product.setPartA(partA);
}
@Override
public void buildPartB(String partB) {
product.setPartB(partB);
}
@Override
public void buildPartC(String partC) {
product.setPartC(partC);
}
@Override
public Product getResult() {
return product;
}
}
指挥者
/**
* 指挥者
*/
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
/**
* 真正构建
*/
public Product construct(String partA, String partB, String partC) {
builder.buildPartA(partA);
builder.buildPartB(partB);
builder.buildPartC(partC);
return builder.getResult();
}
}
客户端
public class Client {
public static void main(String[] args) {
Builder builder = new ProductBuilder();
Director director = new Director(builder);
Product product = director.construct("AAA", "BBB", "CCC");
product.show();
}
}
一般情况下,我们会使用静态内部类的方法来实现建造者模式,在一个产品类内部自动带有一个具体建造者,不再需要建造者接口和指挥者,这样使建造者模式更加简洁。
public class Product {
private String partA;
private String partB;
private String partC;
private Product(ProductBuilder builder) {
this.partA = builder.partA;
this.partB = builder.partB;
this.partC = builder.partC;
}
public static ProductBuilder builder() {
return new ProductBuilder();
}
public void show() {
System.out.println("partA: " + partA + ",partB: " + partB + ",partC: " + partC);
}
/**
* 具体建造者
*/
public static class ProductBuilder {
private String partA;
private String partB;
private String partC;
public ProductBuilder partA(String partA) {
this.partA = partA;
return this;
}
public ProductBuilder partB(String partB) {
this.partB = partB;
return this;
}
public ProductBuilder partC(String partC) {
this.partC = partC;
return this;
}
public Product build() {
return new Product(this);
}
}
}
客户端代码如下
public class Client {
public static void main(String[] args) {
Product product = Product.builder()
.partA("aaa")
.partB("bbb")
.partC("ccc")
.build();
product.show();
}
}
建造者模式在JDK和Guava中的实现
JDK中实现
JDK中构建字符串的建造者StringBuilder
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence {
...
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
...
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
}
客户端使用
public class TestStringBuilder {
public static void main(String[] args) {
String result = new StringBuilder()
.append(12)
.append(true)
.append("abc")
.toString();
System.out.println(result);
}
}
Guava中实现
Guava中缓存的实现CacheBuilder
public final class CacheBuilder<K, V> {
public CacheBuilder<K, V> expireAfterWrite(long duration, TimeUnit unit) {
checkState(
expireAfterWriteNanos == UNSET_INT,
"expireAfterWrite was already set to %s ns",
expireAfterWriteNanos);
checkArgument(duration >= 0, "duration cannot be negative: %s %s", duration, unit);
this.expireAfterWriteNanos = unit.toNanos(duration);
return this;
}
public CacheBuilder<K, V> initialCapacity(int initialCapacity) {
checkState(
this.initialCapacity == UNSET_INT,
"initial capacity was already set to %s",
this.initialCapacity);
checkArgument(initialCapacity >= 0);
this.initialCapacity = initialCapacity;
return this;
}
public <K1 extends K, V1 extends V> Cache<K1, V1> build() {
checkWeightWithWeigher();
checkNonLoadingCache();
return new LocalCache.LocalManualCache<>(this);
}
}
客户端使用
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.util.concurrent.TimeUnit;
public class TestCacheBuilder {
public static void main(String[] args) {
Cache<String, String> cache = CacheBuilder.newBuilder()
.expireAfterWrite(5, TimeUnit.SECONDS)
.initialCapacity(30)
.softValues()
.recordStats()
.build();
System.out.println(cache);
}
}
Guava中不可变集合的实现
import com.google.common.collect.ImmutableList;
public class TestImmutableList {
public static void main(String[] args) {
ImmutableList<String> list = ImmutableList.<String>builder()
.add("aaa")
.add("bbb")
.add("ccc")
.build();
System.out.println(list);
}
}
总结
优点
- 将产品的构建过程和表现分离,耦合度低,方便扩展。
- 可以更加精细的控制产品的创建过程。
缺点
- 如果产品的内部结构复杂多变,当产品内部发生变化,建造者也要同步修改,后期维护成本较大。
本质
建造者模式的本质就是分离整体构建算法和部件构造。
使用场景
- 需要创建的产品对象内部结构比较复杂,需要分离构建过程和使用,这种情况下可以考虑使用建造者模式。
参考
大战设计模式【17】—— 建造者模式
设计模式(六)——建造者模式(源码StringBuilder分析)
设计模式的征途—6.建造者(Builder)模式
研磨设计模式-书籍