什么是 Repository 模式

Repository 这个词直译过来仓库、仓储的意思。这个意思其实也能反应出 Repository 模式作用。App 开发中少不了对数据的操作,数据的来源可能有很多种:网络、数据库、文件以及内存中的缓存。而 Repository 就相当于一个仓库管理员,管理这些数据的存储。当业务层想要获取或者存储数据时,只需要通过 Repository 的管理员进行操作。这样的好处就是:屏蔽数据来源的操作接口。对于业务层来说不必关心数据存在哪里,以及如何存储的。而且也符合我们组件化/模块化架构设计的思想。即当我们更换数据存储设备时,例如从 Android 系统 Sqlite 数据转换为第三方的数据库时,不会影响到业务逻辑。

设计模式

首先预览一下 Repository 模式的设计类图(欢迎拍砖)

IDataSource 是定义了数据来源接口,是根据具体的业务需要定义。一般来说,有增、删、改、查这几个方法。

LocalRepository 封装的是本地存储方式,实现 IDataSource 接口。

RemoteRepository 封装的是网络存储方式,实现 IDataSource 接口。

其中 LocalRepositoryRemoteRepository 就是代表着各种存储方式的具体实现。而 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 模式的更多相关文章

  1. App 组件化/模块化之路——Android 框架组件(Android Architecture Components)使用指南

    面对越来越复杂的 App 需求,Google 官方发布了Android 框架组件库(Android Architecture Components ).为开发者更好的开发 App 提供了非常好的样本. ...

  2. App 组件化/模块化之路——如何封装网络请求框架

    App 组件化/模块化之路——如何封装网络请求框架 在 App 开发中网络请求是每个开发者必备的开发库,也出现了许多优秀开源的网络请求库.例如 okhttp retrofit android-asyn ...

  3. App 组件化/模块化之路——使用SDK的思路进行模块化设计接口

    在不久之前分享一篇<App 组件化/模块化之路——如何封装网络请求框架>文章介绍了我在项目中封装网络请求框架的思路.开发一个 App 会涉及到很多网络请求 API ,例如登录注册接口.用户 ...

  4. App 组件化/模块化之路——构建开发架构思路

    App 组件化/模块化开发架构思路 随着业务的发展 App 开发技术也越来越成熟,对开发者来说 App 代码量也迅速地增长到一个数量级.对于如何架构 App 已经每个开发者面临的实际问题.好的架构可以 ...

  5. Android 组件化/模块化之路——在展示层搭建MVP结构

    Android 组件化/模块化之路——在展示层搭建MVP结构 什么是MVP Model–View–Presenter (MVP) 源于 Model–View–Controller (MVC) 的结构设 ...

  6. 得到、微信、美团、爱奇艺APP组件化架构实践

    一.背景 随着项目逐渐扩展,业务功能越来越多,代码量越来越多,开发人员数量也越来越多.此过程中,你是否有过以下烦恼? 项目模块多且复杂,编译一次要5分钟甚至10分钟?太慢不能忍? 改了一行代码 或只调 ...

  7. JavaScript 组件化开发之路(一)

    *:first-child{margin-top: 0 !important}.markdown-body>*:last-child{margin-bottom: 0 !important}.m ...

  8. Android 开发:由模块化到组件化(一)

    在Android SDK一文中,我们谈到模块化和组件化,现在我们来聊聊组件化开发背后的哪些事.最早是在广告SDK中应用组件化,但是同样适用于普通应用开发 以下高能,请做好心理准备,看不懂请发私信来交流 ...

  9. [Android Pro] 由模块化到组件化(一)

    cp from : https://blog.csdn.net/dd864140130/article/details/53645290 在Android SDK一文中,我们谈到模块化和组件化,现在我 ...

随机推荐

  1. Struts+jdbc+分页 实例

    根据项目里分页实例,带有注解. package org.tarena.netctoss.dao.impl; import java.sql.Connection; import java.sql.Pr ...

  2. Oracle exp/imp数据导入导出工具基本用法

    一.获取帮助 exp/imp help=y 二.数据导出 1.将数据库完全导出,设置full选项exp system/manager@orcl file=d:\db.dmp full=y 2.导出数据 ...

  3. go 测试sort性能

    package main import "fmt" import "os" import "flag" import "bufio ...

  4. Web设计思想——渐进增强

    最近在拜读一本Web体验相关的书<渐进增强--跨平台用户体验设计 >,阅读后做些总结,消化一下书中的精髓. 在阅读本文前,可以先思考下面几个问题. 1. 浏览网页的目的是什么? 2. 浏览 ...

  5. centos 6.6 ios镜像文件 下载 官网和阿里云两种方式教你下载

    1百度一下:centos 打开打开官网.选择这一项 CET CENTOS 2选择 DVD ISO,双击下载 直接选择左键点击下载 这里需要迅雷 方法 二 打开 https://mirrors.aliy ...

  6. 10分钟轻松学会python turtle绘图

     1. 画布(canvas) 1.1 相关函数: 2. 画笔 2.1 画笔的状态 2.2 画笔的属性 2.3 绘图命令 3. 命令详解 4. 绘图举例 4.1 太阳花 4.2 绘制小蟒蛇 4.3 绘 ...

  7. HTML5 中的拖放

    今天,给大家整理一个html5 拖放. 首先,我们先了解一下什么是拖放? 拖放(Drag 和 drop)是 HTML5 标准的组成部分. 拖放是一种常见的特性,即抓取对象以后拖到另一个位置. 在 HT ...

  8. css清除浮动float

    css清除浮动float 1.分析HTML代码 <div class="outer"> <div class="div1">1</ ...

  9. Unity 游戏框架搭建 (五) 简易消息机制

    什么是消息机制? 23333333,让我先笑一会. 为什么用消息机制?   三个字,解!!!!耦!!!!合!!!!. 我的框架中的消息机制用例: 1.接收者 ``` using UnityEngine ...

  10. 函数的上下文就是函数里面的this是谁

    规律1:函数用圆括号调用,函数的上下文是window对象 比如小题目: function fun(){ var a = 888; alert(this.a); //实际上访问的是window.a } ...