什么是 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