从Retrofit/Okhttp源码 学习设计模式-建造者模式
Posted 涂程
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从Retrofit/Okhttp源码 学习设计模式-建造者模式相关的知识,希望对你有一定的参考价值。
建造者模式
首先我们先大致熟悉下通常的建造者模式
建造者模式(Builder Pattern)也叫生成器模式,其定义如下:将一个对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式的通用类图如图所示:
Product产品类 Builder抽象建造者
- 规范产品的组建,一般是由子类实现。
ConcreteBuilder
- 实现抽象类定义的所有方法,并且返回一个组建好的对象。
Director导演类
产品类
public class Product {
public
public void doSomething(){
// 独立业务逻辑
}
}
抽象建造者
public abstract class Builder {
// 设置产品的不同成分,已获得不同的产品
public abstract Builder setPart();
// 建造产品
public abstract Product buildProduct();
}
public class ConcreteProduct extends Builder {
private Product product = new Product();
public Builder setPart(){
/*
* 产品类的内部逻辑
*/
...
return this;
}
// 创建一个产品
public Product build(){
return product;
}
}
导演类
public class Director {
private Builder builder = new ConcreteProduct();
// 构建不同的产品
public Product getAProduct(){
return build.setPart().build();
}
}
建造者模式的优点:
- 封装性
使用建造者模式可以使客户端不必知道产品内部组成的细节。
- 建造者独立,容易扩展
- 便于控制细节风险
建造者模式的使用场景
- 相同的方法,不同的执行顺序,产生不同的事件结果时,可以采用建造者模式
- 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时,则可以使用该模式。
- 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适
- 在对象创建过程中会使用到系统中的一些其他对象,这些对象在产品对象的创建过程中不易得到时,也可以采用建造者模式封装该对象的创建过程。
Retrofit中的构建者模式
OkHttpClient:这个是整个OkHttp的核心管理类,内部包含了请求调度器(Dispatcher),请求拦截器(interceptors),代理,读写超时时间等各种需要配置的对象。这里不就符合前面提到的建造者模式使用场景提到的那几点吗!
多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时,则可以使用该模式。
这些配置的对象就是构建OkhttpClient的多个部件/零件。配置不同,导致的运行结果也不同。就像connectTimeout配置的超时时间不同,导致请求结果允许超时时间也不同。
产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适
在对象创建过程中会使用到系统中的一些其他对象,这些对象在产品对象的创建过程中不易得到时,也可以采用建造者模式封装该对象的创建过程。
这里两点可以合并起来看。OkhttpClient的很多配置对象,如CertificatePinner、protocols这些对象在OkhttpClient的创建过程中不易得到,且创建麻烦。我们应该用建造者模式封装该对象的过程。而且用户不应该知道如此多的创建细节,用户只是要创建一个OkhttpClient对象。不然就违反了迪米特法则了。我们来看下OkhttpClient是具体是怎么实现建造者模式
open class OkHttpClient internal constructor(
builder: Builder
) : Cloneable, Call.Factory, WebSocket.Factory {
@get:JvmName("dispatcher") val dispatcher: Dispatcher = builder.dispatcher
@get:JvmName("connectionPool") val connectionPool: ConnectionPool = builder.connectionPool
/**
* Returns an immutable list of interceptors that observe the full span of each call: from before
* the connection is established (if any) until after the response source is selected (either the
* origin server, cache, or both).
*/
@get:JvmName("interceptors") val interceptors: List<Interceptor> =
builder.interceptors.toImmutableList()
/**
* Returns an immutable list of interceptors that observe a single network request and response.
* These interceptors must call [Interceptor.Chain.proceed] exactly once: it is an error for
* a network interceptor to short-circuit or repeat a network request.
*/
@get:JvmName("networkInterceptors") val networkInterceptors: List<Interceptor> =
builder.networkInterceptors.toImmutableList()
...
}
OKhttpClient构造函数持有builder的依赖,然后其成员变量通过构造函数获取的builder对象,获取其相应的配置对象。然后我们在看Builder类。
class Builder constructor() {
internal var dispatcher: Dispatcher = Dispatcher()
internal var connectionPool: ConnectionPool = ConnectionPool()
internal val interceptors: MutableList<Interceptor> = mutableListOf()
internal val networkInterceptors: MutableList<Interceptor> = mutableListOf()
internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()
internal var retryOnConnectionFailure = true
internal var authenticator: Authenticator = Authenticator.NONE
internal var followRedirects = true
....
internal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULT
internal var certificateChainCleaner: CertificateChainCleaner? = null
internal var callTimeout = 0
internal var connectTimeout = 10_000
internal var readTimeout = 10_000
internal var writeTimeout = 10_000
internal var pingInterval = 0
internal var routeDatabase: RouteDatabase? = null
/**
* Sets the dispatcher used to set policy and execute asynchronous requests. Must not be null.
*/
fun dispatcher(dispatcher: Dispatcher) = apply {
this.dispatcher = dispatcher
}
/**
* Sets the connection pool used to recycle HTTP and HTTPS connections.
*
* If unset, a new connection pool will be used.
*/
fun connectionPool(connectionPool: ConnectionPool) = apply {
this.connectionPool = connectionPool
}
/**
* Returns a modifiable list of interceptors that observe the full span of each call: from
* before the connection is established (if any) until after the response source is selected
* (either the origin server, cache, or both).
*/
fun interceptors(): MutableList<Interceptor> = interceptors
fun sslSocketFactory(
sslSocketFactory: SSLSocketFactory,
trustManager: X509TrustManager
) = apply {
if (sslSocketFactory != this.sslSocketFactoryOrNull || trustManager != this.x509TrustManagerOrNull) {
this.routeDatabase = null
}
this.sslSocketFactoryOrNull = sslSocketFactory
this.certificateChainCleaner = CertificateChainCleaner.get(trustManager)
this.x509TrustManagerOrNull = trustManager
}
fun addInterceptor(interceptor: Interceptor) = apply {
interceptors += interceptor
}
...
fun build(): OkHttpClient = OkHttpClient(this)
}
}
这里的Builder类实际上是OkhttpClient的内部类,也就是产品类的内部类。它是一个具体建造者。 Builder类默认的成员变量会对OkhttpClient的创建所需的对象进行一些默认创建初始化,并会提供一些配置方法,让用户也能灵活控制一些OkhttpClient的创建过程。像拦截器的添加,sslSocketFactory方法,他们返回类型都为Builder。然后通过build()方法直接完成OkhttpClient的构建。
总结
建造者模式的优点:
- 封装性
使用建造者模式可以使客户端不必知道产品内部组成的细节。
- 建造者独立,容易扩展
- 便于控制细节风险
建造者模式的使用场景
- 相同的方法,不同的执行顺序,产生不同的事件结果时,可以采用建造者模式
- 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时,则可以使用该模式。
- 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适
- 在对象创建过程中会使用到系统中的一些其他对象,这些对象在产品对象的创建过程中不易得到时,也可以采用建造者模式封装该对象的创建过程
最后小编在这分享一份,我在学习提升时,从网上收集整理了一些 android 开发相关的学习文档、面试题、Android 核心笔记等等文档,希望能帮助到大家学习提升,如有需要参考的可以直接去我 CodeChina地址:https://codechina.csdn.net/u012165769/Android-T3 访问查阅。
以上是关于从Retrofit/Okhttp源码 学习设计模式-建造者模式的主要内容,如果未能解决你的问题,请参考以下文章