在设计模式里,建造者模式你可能听起来有点陌生,可是一提到Builder模式,你可能就会稍微有点印象。这 个印象可能并非来源于你曾经写过Builder模式。而是在日常编程的时候,总会碰到一个 xxx.Builder() 类。 这个Builder类就是咱们常常在无心中用到的Builder模式,也成为建造者模式。git
咱们总会在无心中用到一些Builder模式,你可能如今想不起来,那么我能够举几个例子稍微提醒一下你!github
这下是否是有了点印象。若是你稍加追究就会发现,不管是 Retrofit ,仍是 OkHttpClient 亦或是 AlertDialog ,他们都有一个共同的特色。就是都有一个Builder类。看到这你可能在想,这不是废话嘛。哈哈的确是废话,不过这几个都有一个共同的特色就是,他们的构造方法都不是 public 修饰的而是 protect 修饰的。而惟一可以构造返回他们自己对象的就是他们各自 Builder类 重的 build() 或者 create() 方法。而我说的是否正确呢。下面分别上图或者源码证实一下!编程
/**
* OkHttpClient源码
*/
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
final int connectTimeout;
final int readTimeout;
final int writeTimeout;
final int pingInterval;
public OkHttpClient() {
this(new Builder());
}
OkHttpClient(Builder builder) {
this.connectTimeout = builder.connectTimeout;
this.readTimeout = builder.readTimeout;
this.writeTimeout = builder.writeTimeout;
this.pingInterval = builder.pingInterval;
}
//中间省略...
public static final class Builder {
int connectTimeout;
int readTimeout;
int writeTimeout;
int pingInterval;
public Builder() {
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
Builder(OkHttpClient okHttpClient) {
this.connectTimeout = okHttpClient.connectTimeout;
this.readTimeout = okHttpClient.readTimeout;
this.writeTimeout = okHttpClient.writeTimeout;
this.pingInterval = okHttpClient.pingInterval;
}
public Builder connectTimeout(long timeout, TimeUnit unit) {
connectTimeout = checkDuration("timeout", timeout, unit);
return this;
}
public Builder readTimeout(long timeout, TimeUnit unit) {
readTimeout = checkDuration("timeout", timeout, unit);
return this;
}
public Builder writeTimeout(long timeout, TimeUnit unit) {
writeTimeout = checkDuration("timeout", timeout, unit);
return this;
}
public Builder pingInterval(long interval, TimeUnit unit) {
pingInterval = checkDuration("interval", interval, unit);
return this;
}
public OkHttpClient build() {
return new OkHttpClient(this);
}
}
}
复制代码
这里我把OkHttpClient的源码,缩减了一下,只留下了4个参数。让咱们来看一下OkHttp框架是怎么建立实例的。设计模式
OkHttpClient okHttpClient=new OkHttpClient();
复制代码
那么它内部的参数,都是默认的,没法经过okHttpClient这个实例来设置和修改参数。bash
OkHttpClient.Builder builder=new OkHttpClient.Builder();
OkHttpClient okHttpClient=builder
.readTimeout(5*1000, TimeUnit.SECONDS)
.writeTimeout(5*1000, TimeUnit.SECONDS)
.connectTimeout(5*1000, TimeUnit.SECONDS)
.build();
复制代码
使用Builder建立实例的时候,不但能够链式结构,还能够修改参数 (缘由是由于,Builder类中的源码,每一个方法的返回值都是Builder自己)框架
这里咱们在举一个Retrofit的例子 (代码也会稍微简化)函数
public final class Retrofit {
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
final List<Converter.Factory> converterFactories;
final List<CallAdapter.Factory> adapterFactories;
final @Nullable Executor callbackExecutor;
final boolean validateEagerly;
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
@Nullable 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 Builder newBuilder() {
return new Builder(this);
}
public static final class Builder {
private final Platform platform;
private @Nullable okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private final List<Converter.Factory> converterFactories = new ArrayList<>();
private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private @Nullable 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();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
}
}
复制代码
上面是Retrofit源码,Retrofit和OkHttp的区别就是,构造方法不是public的,不能直接new出来,只能经过 Builder.build(); 返回一个Retrofit实例。post
其实仔细观察以后就会发现。不管时Retrofit仍是OkHttp为何都和传统的Builder模式不同呢,没有Director类,没有抽象建造者类,也没有具体建造者类。那是由于,在使用过程当中,这些库的做者,包括AlertDialog的做者,谷歌的开发人员,都将这三个类简化进了一个Builder类。因此说,咱们在使用用设计模式的时候不要太过死板。而应随机应变,连Google的开发人员都是这样的,咱们固然也能够取其精华去其糟粕。ui
/**
* 做者:jtl
* 日期:Created in 2019/1/28 11:19
* 描述:Person类(Builder模式)
* 更改:
*/
public class Person {
private String name;
private int age;
private Person(Builder builder) {
this.name = builder.name;
this.age = builder.age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Builder newBuilder() {
return new Builder(this);
}
public static class Builder {
private String name;
private int age;
public Builder() {
this.age = 0;
this.name = "";
}
Builder(Person person) {
this.name = person.name;
this.age = person.age;
}
public Builder setAge(int age) {
this.age = age;
return this;
}
public Builder setName(String name) {
this.name = name;
return this;
}
public Person create() {
return new Person(this);
}
}
}
复制代码
这个是相似与Retrofit和OkHttp的Builder设计模式的一个简化Person类。你们能够仿照这个试一下。this
Builder设计模式,以前咱们可能没有使用过,可是一些经典的第三方库,却都使用了,将对象的建立与表示相分离,用户不用关心它的内在是什么样的。只须要知道传给他什么参数。在一些有不少参数的产品类中使用该模式,能够避免咱们在构造函数中传入大量的默认参数来赋值的尴尬好比:
private String name;//姓名
private int age;//年龄
private String height;//身高
private String weight;//体重
private String sex;//性别
private String address;//家庭住址
private String nation;//种族
private String grade;//年纪
private String clazz;//班级
public Person(String name, int age, String height, String weight, String sex, String address, String nation, String grade, String clazz) {
this.name = name;
this.age = age;
this.height = height;
this.weight = weight;
this.sex = sex;
this.address = address;
this.nation = nation;
this.grade = grade;
this.clazz = clazz;
}
复制代码
而使用了Builder模式后,咱们不须要关心Person类内部作了什么样的操做。
/**
* 做者:jtl
* 日期:Created in 2019/1/28 11:19
* 描述:简化的Builder模式
* 更改:
*/
public class Person {
private String name;//姓名
private int age;//年龄
private String height;//身高
private String weight;//体重
private String sex;//性别
private String address;//家庭住址
private String nation;//种族
private String grade;//年纪
private String clazz;//班级
// public Person(String name, int age, String height, String weight, String sex, String address, String nation, String grade, String clazz) {
// this.name = name;
// this.age = age;
// this.height = height;
// this.weight = weight;
// this.sex = sex;
// this.address = address;
// this.nation = nation;
// this.grade = grade;
// this.clazz = clazz;
// }
private Person(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.height = builder.height;
this.weight = builder.weight;
this.sex = builder.sex;
this.address = builder.address;
this.nation = builder.nation;
this.grade = builder.grade;
this.clazz = builder.clazz;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Builder newBuilder() {
return new Builder(this);
}
public static class Builder {
private String name;//姓名
private int age;//年龄
private String height;//身高
private String weight;//体重
private String sex;//性别
private String address;//家庭住址
private String nation;//种族
private String grade;//年纪
private String clazz;//班级
public Builder() {
this.age = 0;
this.name = "";
this.height="150cm";
this.weight="45kg";
this.sex="男";
this.address="";
this.nation="";
this.grade="一年级";
this.clazz="一班";
}
Builder(Person person) {
this.name = person.name;
this.age = person.age;
this.height = person.height;
this.weight = person.weight;
this.sex = person.sex;
this.address = person.address;
this.nation = person.nation;
this.grade = person.grade;
this.clazz = person.clazz;
}
public Builder setAge(int age) {
this.age = age;
return this;
}
public Builder setName(String name) {
this.name = name;
return this;
}
public Builder setHeight(String height) {
this.height = height;
return this;
}
public Builder setWeight(String weight) {
this.weight = weight;
return this;
}
public Builder setSex(String sex) {
this.sex = sex;
return this;
}
public Builder setAddress(String address) {
this.address = address;
return this;
}
public Builder setNation(String nation) {
this.nation = nation;
return this;
}
public Builder setGrade(String grade) {
this.grade = grade;
return this;
}
public Builder setClazz(String clazz) {
this.clazz = clazz;
return this;
}
public Person create() {
return new Person(this);
}
}
}
复制代码
可能有的小伙伴们就要问了:为何不直接给Person类当中的参数,一个set方法呢?这样不就不用Builder模式了嘛。关于这个问题,我是这样理解的,若是咱们给Person类每个参数都设置一个set方法,这样会增长Person类的功能和职责。违反了单一原则,不利于后期的维护。
好了,就说到这儿了。仍是那句老话,风里雨里我都在这里等你。大家的关注和点赞是我写做的最大动力。但愿你们可以给我一点点的动力。动动您的小手。若是文章中有错误的地方,但愿您及时指出,我好改正。让咱们共同进步。别忘了关注和点赞。谢谢您了!!! 另附GitHub源码地址:https://github.com/13046434521/DesignPatterns