今天我们要讲的是设计模式中三种模式(创建型模式、行为型模式、结构型模式)中的创建型模式中的建造者模式,也可以叫 Builder模式,在面向对象中很常用。
建造者模式的关键是将复杂对象的构建过程与它本身的表示分离开,使得同样的构建过程可以创建不同的表示。
这样说可能会有点绕,我们来看一下建造者模块对应的UML图,加深一下理解:
从图中我们可以看出建造者主要分为4种角色:
- Product(产品类) :我们具体需要生成的类对象
- Builder(抽象建造者类):为我们需要生成的类对象,构建不同的模块属性,即:公开构建产品类的属性,隐藏产品类的其他功能
- ConcreteBuilder(具体建造者类):实现我们要生成的类对象
- Director(导演类):确定构建我们的类对象具体有哪些模块属性,在实际应用中可以不需要这个角色,直接通过client处理
首先,我们来定义一个Product类:
public class Product {
ArrayList<String> parts = new ArrayList<String>();
public void add(String part) {
parts.add(part);
}
public void show() {
System.out.println(parts);
}
}
接下来,我们定义抽象的 Builder 类:
public abstract class Builder {
public abstract void buildPart1();
public abstract void buildPart2();
public abstract Product getResult() ;
}
然后,是具体的 Builder 实现类:
public class ConcreteBuilder extends Builder {
private Product product = new Product();
@Override
public void buildPart1() {
product.add("普通产品");
}
@Override
public void buildPart2() {
product.add("高端产品");
}
public Product getResult() {
return product;
}
}
最后则是 Director 类来控制 Builder 的生产过程
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public void construct() {
builder.buildPart1();
builder.buildPart2();
}
}
测试代码
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
director.construct();
Product product = builder.getResult();
product.show();
建造者模式的应用范围很广,不但在Java源码中有,在很多第三方框架中也有实现,比如OkHttp3其中的OkHttpClient和Request也是由建造者模式实现,下面我们看一下OkHttpClient的源码:
public OkHttpClient() {
this(new Builder());
}
// 由builder配置分发器、代理、协议以及自定义拦截器等
OkHttpClient(Builder builder) {
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
this.protocols = builder.protocols;
//省略大段代码
boolean isTLS = false;
for (ConnectionSpec spec : connectionSpecs) {
isTLS = isTLS || spec.isTls();
}
//省略部分代码
if (interceptors.contains(null)) {
throw new IllegalStateException("Null interceptor: " + interceptors);
}
if (
networkInterceptors.contains(null)) {
throw new IllegalStateException("Null network interceptor: " + networkInterceptors);
}
}
public static final class Builder {
public Builder() {
// 分发器、协议、代理的默认参数
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
proxySelector = ProxySelector.getDefault();
if (proxySelector == null) {
proxySelector = new NullProxySelector();
}
}
Builder(OkHttpClient okHttpClient) {
// 反向配置分发器、代理、协议
this.dispatcher = okHttpClient.dispatcher;
this.proxy = okHttpClient.proxy;
this.protocols = okHttpClient.protocols;
// 新增所有自定义拦截器和自定义网络拦截器
this.interceptors.addAll(okHttpClient.interceptors);
this
.networkInterceptors.addAll(okHttpClient.networkInterceptors);
}
// 配置代理
public Builder proxy(@Nullable Proxy proxy) {
this.proxy = proxy;
return this;
}
// 向拦截器链中增加自定义拦截器
public Builder addInterceptor(Interceptor interceptor) {
if (interceptor == null) throw new IllegalArgumentException("interceptor == null");
interceptors.add(interceptor);
return this;
}
// 最后是build()方法,生成OkHttpClient对象
public OkHttpClient build() {
return new OkHttpClient(this);
}
}
在Java源码里,建造者模式最典型的体现就是StringBuilder。
- StringBuilder是一个指挥者同时是一个具体建造者
- AbstractStringBuilder是Appendable的一个是实现类,为具体建造者
- Appendable接口定义了append()方法,是抽象建造者
源码分析:
创建StringBuilder对象时传入字符串,传入的字符串就相当于指定产品类型,需要构建什么样的产品对象
进入到super.append()中,AbstractStringBuilder实现了Appendable,他是具体的建造者,在这里完成了一个具体的操作
Appendable定义了多个append接口,由他的实现类去实现,方便后续的可扩展性