模式定义
建造者模式:将一个复杂产品的创建与表示分离,使得同样的创建过程可以创建不同的表示
客户端不用去关心产品对象的内部组成,只需要关注如何一步一步的去创建复杂对象,建造者模式是一种创建型模式,何为创建型模式? 顾名思义就是创建对象的设计模式,如常用的单例模式,工厂模式等都为创建型模式。
模式结构
建造者模式主要有以下四个角色:
- Builder 抽象建造者
- ConcreteBuilder 具体建造者
- Director 指挥者
- Product 具体产品
代码分析
Product:具体创建的产品对象
public class Product {
private String partA;
private String partB;
private String partC;
public String getPartA() {
return partA;
}
public void setPartA(String partA) {
this.partA = partA;
}
public String getPartB() {
return partB;
}
public void setPartB(String partB) {
this.partB = partB;
}
public String getPartC() {
return partC;
}
public void setPartC(String partC) {
this.partC = partC;
}
}
Builder:抽象建造者
public abstract class Builder {
public Product product = new Product();
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
public Product getResult() {
return product;
}
}
ConcreteBuilder:具体建造者
public class ConcreteBuilder extends Builder{
@Override
public void buildPartA() {
// TODO Auto-generated method stub
product.setPartA("partA");
}
@Override
public void buildPartB() {
// TODO Auto-generated method stub
product.setPartB("partB");
}
@Override
public void buildPartC() {
// TODO Auto-generated method stub
product.setPartC("partC");
}
}
Director:指挥者
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public Product construct() {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
return builder.getResult();
}
}
测试及结果:
public class Test {
public static void main(String[] args) {
ConcreteBuilder builder = new ConcreteBuilder();
Director director = new Director(builder);
Product product = director.construct();
System.out.println(product.getPartA());
System.out.println(product.getPartB());
System.out.println(product.getPartC());
}
}
从测试代码来看,客户端只需要知道具体的创建者类型,并通过指挥者就可以创建想要的对象,无需关系产品内部的具体构造细节,Builder抽象定义了产品的创建方法和返回方法,而真正的实现是ConcreteBuilder,我们也可以定义不同的ConcreteBuilder,可以定义多个ConcreteBuilder。对于客户端而言,Director分离了产品的创建过程,通过调用建造者的一系列方法返回一个完整的产品对象,这样就做到了所谓的创建与表示相分离,且同样的创建过程有不同的表示。在我们日常的使用中,如果只有一个具体的建造者,通常会省略掉具体的建造者和指挥者,Builder自身充当指挥者角色,下面我们通过分析时下比较流行的网络框架Retrofit的创建过程,它就是采用Builder模式来创建对象。PS:很多不错的开源框架都用到了Builder设计模式
实例分析
接下来首先看一下retrofit对象创建的代码
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http:www.baidu.com")
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
retrofit对象创建采用了建造者模式,只不过它省略了ConcreteBuilder和Director这俩个角色,我们来看一下它的源码,这里并不是Retrofit这个类的所有源代码,我删除了一些跟本文内容无关的代码
public final class Retrofit {
final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
final List<Converter.Factory> converterFactories;
final List<CallAdapter.Factory> adapterFactories;
final Executor callbackExecutor;
final boolean validateEagerly;
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
public okhttp3.Call.Factory callFactory() {
return callFactory;
}
/** The API base URL. */
public HttpUrl baseUrl() {
return baseUrl;
}
public List<CallAdapter.Factory> callAdapterFactories() {
return adapterFactories;
}
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public List<Converter.Factory> converterFactories() {
return converterFactories;
}
public Executor callbackExecutor() {
return callbackExecutor;
}
public Builder newBuilder() {
return new Builder(this);
}
public static final class Builder {
private final Platform platform;
private okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private final List<Converter.Factory> converterFactories = new ArrayList<>();
private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private Executor callbackExecutor;
private boolean validateEagerly;
Builder(Platform platform) {
this.platform = platform;
converterFactories.add(new BuiltInConverters());
}
public Builder() {
this(Platform.get());
}
Builder(Retrofit retrofit) {
platform = Platform.get();
callFactory = retrofit.callFactory;
baseUrl = retrofit.baseUrl;
converterFactories.addAll(retrofit.converterFactories);
adapterFactories.addAll(retrofit.adapterFactories);
// Remove the default, platform-aware call adapter added by build().
adapterFactories.remove(adapterFactories.size() - 1);
callbackExecutor = retrofit.callbackExecutor;
validateEagerly = retrofit.validateEagerly;
}
public Builder client(OkHttpClient client) {
return callFactory(checkNotNull(client, "client == null"));
}
public Builder callFactory(okhttp3.Call.Factory factory) {
this.callFactory = checkNotNull(factory, "factory == null");
return this;
}
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
HttpUrl httpUrl = HttpUrl.parse(baseUrl);
if (httpUrl == null) {
throw new IllegalArgumentException("Illegal URL: " + baseUrl);
}
return baseUrl(httpUrl);
}
public Builder baseUrl(HttpUrl baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
adapterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
public Builder callbackExecutor(Executor executor) {
this.callbackExecutor = checkNotNull(executor, "executor == null");
return this;
}
public Builder validateEagerly(boolean validateEagerly) {
this.validateEagerly = validateEagerly;
return this;
}
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
}
}
首先我们来分析下源码中的角色,其中有俩个角色,分别为Retrofit类和其静态内部类Builder,结合之前的建造者模式角色分析,这里的Retrofit其实就是我们要创建的产品Product,但是这里的Builder并不是一个抽象类,而且没有发现之前所分析的具体建造者ConcreteBuilder和指挥者Director,正如上面所说,当只有一个具体的建造者时,我们可以省略掉具体建造者这个角色,如果省略掉具体建造者,那么指挥者也可以一并省略,Builder自身充当建造者与指挥者双角色。那Builder是如何充当这俩个角色的呢?在Builder类中有一系列公开方法且返回值都是自身,其实这些方法就是对Retrofit的成员属性进行了实例化和赋值,Builder类中还有一个重要的Build方法,该方法的返回值是我们要创建的对象Retrofit,Build方法中首先对Retrofit的相关成员属性做了判空操作,最后调用了Retrofit的构造方法返回Retrofit对象并完成了对象的创建。
总结
- 建造者模式属于创建型模式,将一个复杂产品的创建与表示相分离,同样的构建过程有不同的表示。何为复杂产品?其实就是成员属性比较多的产品,客户端无需关心复杂产品的内部构造组成细节,只需要知道具体的建造者类型即可,更多关注如何一步一步创建一个复杂对象。
- 建造者模式优点:客户端无需知道产品内部内部构造组成细节,将产品本身与产品的创建过程解耦;具体的建造者时间相互独立,便于替换或增加新的建造者,客户端通过不同的建造者可以得到不同对象。
- 建造者模式缺点:建造者创建的产品一般具有具有较多相同共同点,其内部组成类似,如果产品之间差异性较大,则不适合用建造者模式,其次,如果产品内部变化复杂,会导致创建很多具体的建造者来对应其变化,这样会导致系统变的很庞大。
- 建造者模式使用场景:需要创建的产品有复杂的内部结构,也就是说成员属性较多,且产品成员属性之间相互依赖,需指定生成顺序。