我们知道,总共是有以下三个主要模块的
- ORM
- 网络请求
- 数据缓存的核心逻辑
按理说ORM和网络请求更加基础,应该先讲,但是,我并不这么做。我要是讲ORM和网络请求,估计很多人就不想看了。众所周知,ORM和网络请求都有大量成熟的开源库来支持了。我本次要编写的框架的重点不是在这两块上,而是这两个模块的桥梁,简单的说,就是整合这两个模块的中间层。
框架我们打算采用Kotlin语言进行编写。
由于我们知道了数据缓存的流程,那么我们直接定义一个控制整体流程的接口。
```
package dora.cache.holder
import dora.db.builder.Condition
/**
* 控制缓存和加载数据的流程。
*/
interface CacheHolder<M> {
/**
* 该类型数据库orm框架的一些初始化操作在这里进行。
*/
fun init()
/**
* 从数据库中加载数据到内存。
*/
fun queryCache(condition: Condition) : M?
/**
* 查询缓存记录数量。
*/
fun queryCacheSize(condition: Condition) : Long
/**
* 移除旧的数据库缓存。
*/
fun removeOldCache(condition: Condition)
/**
* 将最新的数据缓存到数据库。
*/
fun addNewCache(model: M)
}
```
M即我们要缓存的model数据,但它并不完全等同于api接口返回的数据根,后面我们会讲到ResultAdapter结果适配器,我们先认为api接口返回的json直接就是我们要整体缓存的数据。这里还出现了一个Condition类,它是我们定义的一个连接orm框架的桥梁,我们以后通过它来更换orm框架这一层。
```
package dora.db.builder
/**
* 查询条件,它是一个和orm框架整合的协议。
*/
class Condition(
// 条件语句,如 a > ? and a < ? , 或 a > 0
val selection: String,
// 条件参数,如 a > ? and a < ?中两个?的具体值0和100
val selectionArgs: Array<String?>,
// 同sql语句limit的用法
val limit: String? = "",
// 同sql语句order by的用法
val orderBy: String? = "",
// 同sql语句group by的用法
val groupBy: String? = "",
// 同sql语句having的用法
val having: String? = "")
```
我们打算自己写一个orm框架,而如果框架使用者要使用别人的orm框架,则可以通过它来整合,这个我们以后再考虑。
我们自己实现一个CacheHolder。
```
package dora.cache.holder
import dora.db.table.OrmTable
import dora.db.builder.Condition
import dora.db.builder.WhereBuilder
import dora.db.dao.DaoFactory
import dora.db.dao.OrmDao
/**
* 内置的CacheHolder,默认实现。
*/
class DoraCacheHolder<M, T : OrmTable>(var clazz: Class<out OrmTable>) : CacheHolder<M> {
private lateinit var dao: OrmDao<T>
override fun init() {
// 创建指定类型的OrmDao
dao = DaoFactory.getDao(clazz) as OrmDao<T>
}
override fun queryCache(condition: Condition): M? {
return dao.selectOne(WhereBuilder.create(condition)) as M?
}
override fun removeOldCache(condition: Condition) {
dao.delete(WhereBuilder.create(condition))
}
override fun addNewCache(model: M) {
dao.insert(model as T)
}
override fun queryCacheSize(condition: Condition): Long {
return dao.selectCount(WhereBuilder.create(condition))
}
}
```
OrmDao的用法我们暂不细究,它就是用来操作sqlite数据库的。
由于api接口不一定给我们的json数据正好就是我们要缓存的model数据。我们需要定义一个指定数据要缓存的部分的接口Result。
```
package dora.cache.data.adapter
/**
* 如果api接口返回的model并非直接为要缓存的model对象,即非[dora.db.table.OrmTable]的子类,则通过这个接口指定要
* 缓存的数据。
*/
interface Result<M> {
/**
* 真实要缓存的model,返回api接口返回数据的一个属性。
*/
fun getRealModel() : M?
}
```
比如api接口返回json
```
{
"code": "000000",
"message": "请求成功",
"data": {
"username": "dora123",
"score": 0,
"vip": 0,
"token": "token:Android-20220721232231-E84E30B9390CDB64DB6DB2C9AB87846D"
},
"timestamp": 1658416951883
}
```
很明显,这些状态不是我们要缓存的数据,我们真正要缓存的数据是data字段的整体,我们getRealModel就返回model中的data属性作为真实要缓存的model。这样用的话,数据根就要实现Result接口。
我们网络模块那一层则通过ResultAdapter进行适配。
```
package dora.cache.data.adapter
import dora.http.DoraCallback
/**
* 将实现[dora.cache.data.adapter.Result]的api接口返回的model数据适配成框架需要的[dora.http.DoraCallback]
* 对象。
*/
class ResultAdapter<M, R : Result<M>>(val callback: DoraCallback<M>) : DoraCallback<R>() {
/**
* 适配[dora.http.DoraCallback]成功的回调。
*/
override fun onSuccess(model: R) {
model.getRealModel()?.let { callback.onSuccess(it) }
}
/**
* 适配[dora.http.DoraCallback]失败的回调。
*/
override fun onFailure(msg: String) {
callback.onFailure(msg)
}
}
```
网络模块的实现我们暂也不用了解。