组件对外接口设计-易用性

示例

OKHttp网络请求:

FormBody formBody = new FormBody.Builder()
	    .add("pay_fee", String.valueOf(product.getProductPrice()))
        .add("product_name", String.valueOf(product.getProductName()))
        .add("access_token", "")
        .build();

Request request = new Request.Builder()
        .post(formBody)
        .url(createOrderURL)
        .build();

OkHttpClient okHttpClient = new OkHttpClient();
Call call = okHttpClient.newCall(request);
call.enqueue(null);

Glide的图片加载:

Glide.with(this)
        .load(sampledPhotoPath)
        .asBitmap()
        .format(DecodeFormat.ALWAYS_ARGB_8888)
        .skipMemoryCache(true)
        .transform(new FilterEffectBitmapTransformation(this,
                mFilterInfo, sampledPhotoPath))
        .into(mBinding.appBeautyFilterMarkPhotoIv);

调用上面的代码的感觉“爽”,接口简单,方便的网络请求,方便的图片加载。从上面的代码代码看出接口的定义非常易用。我们该怎么写出如此简单易用的接口?下面我们一起探讨一下。

从上面代码可以看出配置的时候的使用了.的一步步的连接起来,其实这种方式采用了Builder模式,使得接入的时候非常方便,而且代码很清晰。

OKHttp结构图:

OKHttp的接口

  • 对外接口
    • OkHttpClient, Builder用于全局的请求配置和作为Call的工厂方法
    • Request,Builder, RequestBody用于构建请求数据
    • Call可执行的网络请求
  • 底层接口执行网络请求,比如Dispather请求分发,Interceptor,Chain等类被上层接口封装,不暴露给client。

Glide的结构图:

Glide的接口:

  • 对外接口:
    • Glide,RequestManager,GenericRequestBuilder封装了底层接口
  • 底层接口是实际的图片加载。基本不暴露给client使用,除非涉及到了相关的配置。

其实上面的对外接口的设计用到了一种设计模式Facade模式。此模式封装子系统,向外提供了更高层的接口主要有以下几个好处:

  • 提高了对外接口的易用性,降低了接入成本
  • 子系统的不想暴露的接口可以隐藏,更好的体现了面向对象的思想。
  • 子系统做兼容,或者是代码重构,亦或是流程修改,只要高层接口不改变,不会影响到client。

从上面我们得出了提高对外接口的易用性的常用的设计方式

  • Builder模式用于配置
  • Facade模式封装子系统来提供对外的高层接口

下面我们就简单介绍一下如何使用这两种设计模式。

设计模式

Builder模式

基础知识,可参考 刘伟的博客。

建造者模式(一)

建造者模式(二)

建造者模式(三)

这个模式在对外接口设计中一般用于配置或者构建复杂对象。

比如OKHttp里的配置:

OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .connectTimeout(10, TimeUnit.SECONDS)
        .build();

为了简化这里只是列举了部分信息。

public static final class Builder {
    int connectTimeout;
    int readTimeout;
  
    public Builder() {
      connectTimeout = 10_000;
      readTimeout = 10_000;
    }

    Builder(OkHttpClient okHttpClient) {
      this.connectTimeout = okHttpClient.connectTimeout;
      this.readTimeout = okHttpClient.readTimeout;
    }
  
    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 OkHttpClient build() {
      return new OkHttpClient(this);
    }
}
public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
  
  final int connectTimeout;
  final int readTimeout;
  
  public OkHttpClient() {
    this(new Builder());
  }

  OkHttpClient(Builder builder) {
    this.connectTimeout = builder.connectTimeout;
    this.readTimeout = builder.readTimeout;
  }

  public int connectTimeoutMillis() {
    return connectTimeout;
  }

  public int readTimeoutMillis() {
    return readTimeout;
  }
  
}
  • Builder构建OkHttpClient的时候,客户端可以配置信息,然后调用build就可以构建成功。
  • Builder构建OKHttpClient的时候,readTimeout接口或者connectTimeout接口返回Builder对象,这样的客户端调用的时候只需要用.来连接相关的方法,更加方便。

大家也可以查看GenericRequestBuilder如何构建Request的,或者Android的Intent的类,来了解Builder的使用。

实现的技巧:

  • 实现的时候必要参数可以在构造函数中传递,其他的使用接口设置
  • Builder的类返回的函数可以返回当前的对象,以此可以使用调用的.的符号记性连接。

Facade设计模式

为子系统的一组接口提供一个一致的界面,Facade模式定义了一些高层接口,这些接口使得子系统更加容易使用。

下面以我以前做的游戏联运的SDK为例。

对外提供接口这里使用了Facade模式,

  • MTOnlieGameSDK为主要的对外的高层接口类。
  • MTOnlieGameSDK封装了其他子系统,MTAccountManager,MTPayManager
  • 同时MTAccountManager,MTPayManager也使用了Facade模式,MTAccountManager封装帐号SDK,MTPayManager封装了与支付APK的通信。

Notice:

  1. 封装了子系统对外的接口得到简化,提高了对外接口的易用性。
  2. 使用Facade模式封装更高层的接口,避免了不必要的接口的暴露,同时子系统与客户端代码分离,提高了代码的独立性。比如更改MTAccountManager的实现不会影响到client的代码修改。

此外在层次结构接口中引入Facade模式封装每个层级,可以简化层级之间的依赖。

其他问题

  • 接口的暴露,不需要的接口尽量不暴露用户。
  • 参数的数量的问题,一方面尽量减少参数,一般参数3个左右为宜,多了可以使用封装成类进行传递。
  • 参数依赖抽象类,比如Activity和Context的使用,能使用Context尽量不要使用Activity等等。也就是尽量使用接口而不是具体类。
  • 工厂方法或者抽象工厂来创建对象。比如OKHttp的Call.Factory。

注意:

  1. 设计模式的使用只是为了得到好的代码设计,而过度使用会造成冗余,三思再用。
  2. 设计模式的使用不要过于依赖所谓的类图或者结构图,往往稍微变化的设计模式更好用。

参考资料

  • 设计模式-可复用面向对象软件的基础 只服四人帮的这本书,虽然例子和内容过时了,但设计思想杠杠的。
  • LoveLion的博客

`

你可能感兴趣的:(Android,组件设计,库设计)