App 組件化/模塊化之路——Repository 模式


什么是 Repository 模式

Repository 這個詞直譯過來倉庫、倉儲的意思。這個意思其實也能反應出 Repository 模式作用。App 開發中少不了對數據的操作,數據的來源可能有很多種:網絡、數據庫、文件以及內存中的緩存。而 Repository 就相當於一個倉庫管理員,管理這些數據的存儲。當業務層想要獲取或者存儲數據時,只需要通過 Repository 的管理員進行操作。這樣的好處就是:屏蔽數據來源的操作接口。對於業務層來說不必關心數據存在哪里,以及如何存儲的。而且也符合我們組件化/模塊化架構設計的思想。即當我們更換數據存儲設備時,例如從 Android 系統 Sqlite 數據轉換為第三方的數據庫時,不會影響到業務邏輯。

設計模式

首先預覽一下 Repository 模式的設計類圖(歡迎拍磚)

Repository模式

IDataSource 是定義了數據來源接口,是根據具體的業務需要定義。一般來說,有增、刪、改、查這幾個方法。

LocalRepository 封裝的是本地存儲方式,實現 IDataSource 接口。

RemoteRepository 封裝的是網絡存儲方式,實現 IDataSource 接口。

其中 LocalRepositoryRemoteRepository 就是代表着各種存儲方式的具體實現。而 RepositoryFactory就是傳說中的“倉庫管理員”,管理着各種存儲方式,它也是業務層數據層交互的橋梁。

Show me the code

假設目前有個業務是獲取遠程數據的需求,如果本地有緩存數據則從本地獲取,否則從網絡中獲取。這樣的業務邏輯很常見,我們用 Repository

模式進行封裝。

首先預覽代碼總體結構

repository-code-structure

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM