前言
将构造 Retrofit 时所需要的材料隔离开来,利用依赖倒置这个原则,优雅地烘烤出美味的 Retrofit 实例。
类图
来自《Head First 设计模式》抽象工厂一节中披萨店卖披萨的启发,我们也将 Retrofit 看做一样商品,来设计它。

RetrofitWrapper
我们需要的产品,内部包含了一个 Retrofit 的引用。我们将这个类抽象,构造 Retrofit 的原料来自另一个抽象类:RetrofitWrapperFactory,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
public abstract class RetrofitWrapper {
protected Retrofit mRetrofit;
public RetrofitWrapper(RetrofitWrapperFactory retrofitWrapperFactory) {
mRetrofit = new Retrofit.Builder().baseUrl(retrofitWrapperFactory.provideBaseUrl()) .client(retrofitWrapperFactory.createOkHttpClient()) .addConverterFactory(retrofitWrapperFactory.createGsonConverterFactory()) .addCallAdapterFactory(retrofitWrapperFactory.createRxJavaCallAdapter()) .build(); }
public Retrofit getRetrofit() {
return mRetrofit; } }
|
RetrofitWrapperFactory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
public interface RetrofitWrapperFactory {
String provideBaseUrl();
OkHttpClient createOkHttpClient();
Converter.Factory createGsonConverterFactory();
CallAdapter.Factory createRxJavaCallAdapter(); }
|
RetrofitWrapperStore
兜售 RetrofitWrapper 的商店,这里商店类还继承了一个 RetrofitApiProvider 接口,用来对外暴露创建 Retrofit Api Service 的接口。
1 2 3 4 5 6 7 8 9
|
public abstract class RetrofitWrapperStore implements RetrofitApiProvider {
protected abstract RetrofitWrapper createRetrofitWrapper(); }
|
1 2 3 4 5 6
| public interface RetrofitApiProvider {
<T> T provideApi(Class<T> service); }
|
举栗时间
具体产品类
1 2 3 4 5 6 7
| public class PeroRetrofitWrapper extends RetrofitWrapper {
public PeroRetrofitWrapper(RetrofitWrapperFactory retrofitWrapperFactory) { super(retrofitWrapperFactory); } }
|
具体工厂类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| public class PeroRetrofitWrapperFactory implements RetrofitWrapperFactory {
private static final int DEFAULT_CONNECT_TIME_OUT = 10;
private static final String TEST_SERVER_URL = "http://192.168.199.182:3000";
@Override public OkHttpClient createOkHttpClient() {
return new OkHttpClient.Builder().connectTimeout(DEFAULT_CONNECT_TIME_OUT, TimeUnit.SECONDS) .addInterceptor(provideHttpLoggingInterceptor()) .addNetworkInterceptor(provideTokenInterceptor()) .build(); }
private Interceptor provideHttpLoggingInterceptor() {
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return httpLoggingInterceptor; }
private Interceptor provideTokenInterceptor() {
return new TokenInterceptor(); }
@Override public CallAdapter.Factory createRxJavaCallAdapter() {
return RxJavaCallAdapterFactory.create(); }
@Override public Converter.Factory createGsonConverterFactory() {
Gson gson = new GsonBuilder().registerTypeAdapterFactory(provideParamsAdapterFactory()).create();
return GsonConverterFactory.create(gson); }
private TypeAdapterFactory provideParamsAdapterFactory() {
return new ParamsAdapterFactory(); }
@Override public String provideBaseUrl() {
return TEST_SERVER_URL; } }
|
具体商店类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public final class PeroRetrofitWrapperStore extends RetrofitWrapperStore {
private RetrofitWrapper mRetrofitWrapper;
public PeroRetrofitWrapperStore() {
mRetrofitWrapper = createRetrofitWrapper(); }
private static class SingletonHolder {
private static final PeroRetrofitWrapperStore sInstance = new PeroRetrofitWrapperStore(); }
public static PeroRetrofitWrapperStore getInstance() {
return SingletonHolder.sInstance; }
@Override protected RetrofitWrapper createRetrofitWrapper() {
return new PeroRetrofitWrapper(new PeroRetrofitWrapperFactory()); }
@Override public <T> T provideApi(Class<T> service) {
return mRetrofitWrapper.getRetrofit().create(service); } }
|
如何调用?
在实际项目中,PeroRetrofitWrapper 和 PeroRetrofitWrapperFactory 可以作为 PeroRetrofitWrapperStore 的静态内部类,从而屏蔽外部可见性。毕竟,现实生活中,我们买披萨也是去商店购买,而不会跑到原料工厂自己动手造披萨对吧2333。
1 2 3 4 5 6 7 8
|
private void fetchPinCode(final String phoneNum) {
PeroRetrofitWrapperStore.getInstance() .provideApi(PeroApi.UserApi.class) .fetchSmsCode(new Params.Builder().put("phoneNumber", phoneNum).create())
|
思考&改进
示例代码里已经将 RetrofitWrapper 单例化了,而创建 Service Api,其实还是在 new object。
1 2 3 4 5 6
| @Override public <T> T provideApi(Class<T> service) {
return mRetrofitWrapper.getRetrofit().create(service); }
|
如果有需要,也可以将 Api Service 进行单例化。
总结
有 new 关键字的地方我们就应该谨慎,是否耦合得太厉害,是否可以用工厂模式来解耦。当然,因为我的项目里暂时还没有 Dagger2,所以自己动手,实现解耦,如果有 Dagger2 的话,就不用这么麻烦了233。