1.1 元编程的需求背景

我们在编写程序时经常会遇到一个问题—重复,而工程师最不能忍受的就是重复。重复意味着低效,也意味着低级。我们造的每一个“轮子”在某种意义上都是为了解决重复的问题。业内也有一句名言:“不要重复你自己(Don't repeat yourself)。”

然而在实际的业务场景中,我们经常会见到大量重复或者相似的模板代码,这些代码很多时候难以使用编程语言的基本特性进行抽象,因此我们不得不忍受它们的存在。

Java的Getter方法和Setter方法就是很典型的例子,如代码清单1-1所示。

代码清单1-1 Java的Getter方法和Setter方法

幸运的是,Kotlin把属性作为正式的特性提供给开发者,使得开发者终于不用忍受充斥着Getter和Setter的模板代码了,如代码清单1-2所示。

代码清单1-2 Kotlin的属性

不过,不是所有模板代码问题都能通过添加语法特性解决。

业务代码中最常见的网络请求就是高度模板化的代码。不同的业务接口虽然各不相同,但网络请求本身的代码极为相似。以OkHttp为例,如代码清单1-3所示。

代码清单1-3 使用OkHttp发送网络请求

我们定义了两个函数getUser和getRepository,分别用于请求GitHub的API以获取用户和仓库的相关信息。这两个函数除了参数、返回值和请求的URL不同以外,剩下的代码完全相同,而这部分相同的代码才是这两个函数的主体内容。如果调用者希望接口同时提供异步回调和协程的版本,情况只会更糟糕。异步回调和协程版本的接口函数如代码清单1-4所示。

代码清单1-4 异步回调和协程版本的接口函数

在实际的业务场景中,请求几十甚至上百个接口是非常常见的事情。可以想象,重复的接口代码实现将会给项目带来巨大的维护成本。

解决此类问题最常用的手段就是元编程。Kotlin提供了非常丰富的元编程手段,包括运行时反射(Kotlin JVM)、编译时符号处理等。

Retrofit就是一个充分运用运行时反射能力来简化HTTP接口代码的框架。它可以以非常优雅的方式解决代码清单1-3和代码清单1-4中存在的问题,如代码清单1-5所示。

代码清单1-5 使用Retrofit定义HTTP接口函数

3.3节将对Retrofit的工作机制进行剖析。