App 组件化/模块化之路——Repository 模式
什么是 Repository 模式
Repository 这个词直译过来仓库、仓储的意思。这个意思其实也能反应出 Repository 模式作用。App 开发中少不了对数据的操作,数据的来源可能有很多种:网络、数据库、文件以及内存中的缓存。而 Repository 就相当于一个仓库管理员,管理这些数据的存储。当业务层想要获取或者存储数据时,只需要通过 Repository 的管理员进行操作。这样的好处就是:屏蔽数据来源的操作接口。对于业务层来说不必关心数据存在哪里,以及如何存储的。而且也符合我们组件化/模块化架构设计的思想。即当我们更换数据存储设备时,例如从 Android 系统 Sqlite 数据转换为第三方的数据库时,不会影响到业务逻辑。
设计模式
首先预览一下 Repository 模式的设计类图(欢迎拍砖)
IDataSource
是定义了数据来源接口,是根据具体的业务需要定义。一般来说,有增、删、改、查这几个方法。
LocalRepository
封装的是本地存储方式,实现 IDataSource
接口。
RemoteRepository
封装的是网络存储方式,实现 IDataSource
接口。
其中 LocalRepository
与 RemoteRepository
就是代表着各种存储方式的具体实现。而 RepositoryFactory
就是传说中的“仓库管理员”,管理着各种存储方式,它也是业务层与数据层交互的桥梁。
Show me the code
假设目前有个业务是获取远程数据的需求,如果本地有缓存数据则从本地获取,否则从网络中获取。这样的业务逻辑很常见,我们用 Repository
模式进行封装。
首先预览代码总体结构
IDataSource
public interface IDataSource<T> {
void add(T t); void delete(T t); void update(T t); List<T> queryAll(); T queryById(int id);
}
LocalRepository
public class LocalRepository implements IDataSource<Data> { public LocalRepository() {
} @Override
public void add(Data data) {
DBHelper.get().add(data);
} @Override
public void delete(Data data) {
DBHelper.get().delete(data);
} @Override
public void update(Data data) {
DBHelper.get().update(data);
} @Override
public List<Data> queryAll() {
return DBHelper.get().queryAll();
} @Override
public Data queryById(int id) {
return DBHelper.get().queryById(id);
}
}
RemoteRepository
public class RemoteRepository implements IDataSource<Data> {
@Override
public void add(Data data) {
DataApi.get().add(data);
} @Override
public void delete(Data data) {
DataApi.get().delete(data);
} @Override
public void update(Data data) {
DataApi.get().update(data);
} @Override
public List<Data> queryAll() {
return DataApi.get().queryAll();
} @Override
public Data queryById(int id) {
return DataApi.get().queryById(id);
}
}
RepositoryFactory
public class RepositoryFactory implements IDataSource<Data> {
private IDataSource<Data> local;
private IDataSource<Data> remote; private static RepositoryFactory INSTANCE;
/**
* 使用Map实现一个内存缓存
*/
HashMap<String, Data> mCache = new HashMap<>(); private RepositoryFactory(@NonNull IDataSource<Data> local, @NonNull IDataSource<Data> remote) {
this.local = local;
this.remote = remote;
} public static RepositoryFactory get(@NonNull IDataSource<Data> local, @NonNull IDataSource<Data> remote) {
if (INSTANCE == null) {
INSTANCE = new RepositoryFactory(local, remote);
}
return INSTANCE;
} public static RepositoryFactory get() {
if (INSTANCE == null) {
INSTANCE = new RepositoryFactory(new LocalRepository(), new RemoteRepository());
}
return INSTANCE;
} public void destory() {
INSTANCE = null;
} @Override
public void add(Data data) {
local.add(data);
remote.add(data);
mCache.put(String.valueOf(data.id), data);
} @Override
public void delete(Data data) {
local.delete(data);
remote.delete(data);
mCache.remove(String.valueOf(data.id));
} @Override
public void update(Data data) {
local.update(data);
remote.update(data);
mCache.put(String.valueOf(data.id), data);
} /**
* @return
*/
@Override
public List<Data> queryAll() {
List<Data> list = local.queryAll();
if (list.isEmpty()) {
list = remote.queryAll();
}
return list;
} /**
* 这里使用三级缓存获取一个Data对象
*
* @param id
* @return
*/
@Override
public Data queryById(int id) { Data data = mCache.get(String.valueOf(id));
if (data == null) {
data = local.queryById(id);
}
if (data == null) {
data = remote.queryById(id);
}
if (data != null) {
mCache.put(String.valueOf(id), data);
}
return data;
} }
使用示例
Flowable.fromCallable(new Callable<List<Data>>() {
@Override
public List<Data> call() throws Exception {
List<Data> dataList = RepositoryFactory.get().queryAll();
return dataList;
}
}).observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Consumer<List<Data>>() {
@Override
public void accept(@NonNull List<Data> datas) throws Exception {
textView.setText("data size:" + datas.size());
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
textView.setText(throwable.getMessage());
}
});
这里是直接使用了 RxJava2 进行调用,因为 Repository 是对数据的请求和访问,这个是耗时操作,故需要放在后台线程中进行。在实际的项目中一般都会使用 MVP 来封装这一层。
本文Demo :wecodexyz/Componentization
参考文献:googlesamples/android-architecture
App 组件化/模块化之路——Repository 模式的更多相关文章
- App 组件化/模块化之路——Android 框架组件(Android Architecture Components)使用指南
面对越来越复杂的 App 需求,Google 官方发布了Android 框架组件库(Android Architecture Components ).为开发者更好的开发 App 提供了非常好的样本. ...
- App 组件化/模块化之路——如何封装网络请求框架
App 组件化/模块化之路——如何封装网络请求框架 在 App 开发中网络请求是每个开发者必备的开发库,也出现了许多优秀开源的网络请求库.例如 okhttp retrofit android-asyn ...
- App 组件化/模块化之路——使用SDK的思路进行模块化设计接口
在不久之前分享一篇<App 组件化/模块化之路——如何封装网络请求框架>文章介绍了我在项目中封装网络请求框架的思路.开发一个 App 会涉及到很多网络请求 API ,例如登录注册接口.用户 ...
- App 组件化/模块化之路——构建开发架构思路
App 组件化/模块化开发架构思路 随着业务的发展 App 开发技术也越来越成熟,对开发者来说 App 代码量也迅速地增长到一个数量级.对于如何架构 App 已经每个开发者面临的实际问题.好的架构可以 ...
- Android 组件化/模块化之路——在展示层搭建MVP结构
Android 组件化/模块化之路——在展示层搭建MVP结构 什么是MVP Model–View–Presenter (MVP) 源于 Model–View–Controller (MVC) 的结构设 ...
- 得到、微信、美团、爱奇艺APP组件化架构实践
一.背景 随着项目逐渐扩展,业务功能越来越多,代码量越来越多,开发人员数量也越来越多.此过程中,你是否有过以下烦恼? 项目模块多且复杂,编译一次要5分钟甚至10分钟?太慢不能忍? 改了一行代码 或只调 ...
- JavaScript 组件化开发之路(一)
*:first-child{margin-top: 0 !important}.markdown-body>*:last-child{margin-bottom: 0 !important}.m ...
- Android 开发:由模块化到组件化(一)
在Android SDK一文中,我们谈到模块化和组件化,现在我们来聊聊组件化开发背后的哪些事.最早是在广告SDK中应用组件化,但是同样适用于普通应用开发 以下高能,请做好心理准备,看不懂请发私信来交流 ...
- [Android Pro] 由模块化到组件化(一)
cp from : https://blog.csdn.net/dd864140130/article/details/53645290 在Android SDK一文中,我们谈到模块化和组件化,现在我 ...
随机推荐
- Django Nginx反代 获取真实ip
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px "Andale Mono"; color: #28fe14; backgr ...
- Vulkan Tutorial 15 Framebuffers
操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 我们在前面的章节中已经讨论了很多次framebuffers帧缓冲区,到目前为止我们配 ...
- C#开发移动应用系列(2.使用WebView搭建WebApp应用)
前言 上篇文章地址:C#开发移动应用系列(1.环境搭建) 嗯..一周了 本来打算2天一更的 - - ,结果 出差了..请各位原谅.. 今天我们来讲一下使用WebView搭建WebApp应用. 说明一下 ...
- GA代码中的细节
GA-BLX交叉-Gaussion变异 中的代码细节: 我写了一个GA的代码,在2005测试函数上一直不能得到与实验室其他同学类似的数量级的结果.现在参考其他同学的代码,发现至少有如下问题: 1.在交 ...
- 表单格式化插件jquery.serializeJSON
前言 前端在处理含有大量数据提交的表单时,除了使用Form直接提交刷新页面之外,经常碰到的需求是收集表单信息成数据对象,Ajax提交. 而在处理复杂的表单时,需要一个一个区手动判断处理字段值,显得非常 ...
- 神奇的 conic-gradient 圆锥渐变
感谢 LeaVerou 大神,让我们可以提前使用上这么美妙的属性. conic-gradient 是个什么?说到 conic-gradient ,就不得不提的它的另外两个兄弟: linear-grad ...
- Sql_Case_When用法
http://wenku.baidu.com/link?url=XBnkUzGtiJFhTnQk5HbmdgndhVEYJdcfDEhSEIFeTRn9-41KMLf_49wKiydNCF-4g3Qi ...
- bootstrap-table前台和后台分页对json格式的要求
Bootstrap是一款前端非常流行的框架,其中的表格更为大家经常使用.大家都知道表格的分页分为前台和后台分页,也就是表格配置中sidePagination属性,当sidePagination: &q ...
- Ubuntu下使用nginx和nginx-rtmp-module搭建流媒体服务器的正确姿势
之前在使用nginx和nginx-rtmp-module搭建流媒体服务器的时候遇到一个很尴尬的问题,就是在把nginx-rtmp-module模块添加到nginx中去的时候,我最开始采取的做法是先卸载 ...
- Window文件目录挂载(mount)到linux系统目录下
1.先在windows下面共享需要挂载的目录. 2.确保linux与windows是在同一个局域网当中. 3.在linux下面创建一个需要挂载到的目录. 4.然后点击"添加",建立 ...