Android存储库设计如何避免样板代码

时间:2018-02-02 12:09:39

标签: android sqlite repository-pattern android-room

我的应用程序有本地 SQLite(会议室)数据库我正在使用缓存数据的存储库设计模式(稍后我将它连接到远程存储库)。我有三个不同的数据库表 TableOne TableTwo TableThree 。我对这些开发模式真的很陌生,无法找到准确的信息如何使用所有帮助都会有所帮助

我有以下问题:

  1. 我应该为每个表使用一个DAO类还是不同的DAO?那有什么不同吗?
  2. 我应该使用一个存储库类吗?
  3. 缓存应该如何适用于所有这些表?我应该将每个表加载到不同的缓存吗?如果没有如何从同一个缓存中获取数据?
  4. 以下是当前使用的缓存系统的代码:

        /**
     * Concrete implementation to load tasks from the data sources into a cache.
     *
     *
     * For simplicity, this implements a dumb synchronisation between locally persisted data and data
     * obtained from the server, by using the remote data source only if the local database doesn't
     * exist or is empty.
     */
    class TasksRepository(
            val tasksRemoteDataSource: TasksDataSource,
            val tasksLocalDataSource: TasksDataSource
    ) : TasksDataSource {
    
        /**
         * This variable has public visibility so it can be accessed from tests.
         */
        var cachedTasks: LinkedHashMap<String, Task> = LinkedHashMap()
    
        /**
         * Marks the cache as invalid, to force an update the next time data is requested. This variable
         * has package local visibility so it can be accessed from tests.
         */
        var cacheIsDirty = false
    
        /**
         * Gets tasks from cache, local data source (SQLite) or remote data source, whichever is
         * available first.
         *
         *
         * Note: [LoadTasksCallback.onDataNotAvailable] is fired if all data sources fail to
         * get the data.
         */
        override fun getTasks(callback: TasksDataSource.LoadTasksCallback) {
            // Respond immediately with cache if available and not dirty
            if (cachedTasks.isNotEmpty() && !cacheIsDirty) {
                callback.onTasksLoaded(ArrayList(cachedTasks.values))
                return
            }
    
            if (cacheIsDirty) {
                // If the cache is dirty we need to fetch new data from the network.
                getTasksFromRemoteDataSource(callback)
            } else {
                // Query the local storage if available. If not, query the network.
                tasksLocalDataSource.getTasks(object : TasksDataSource.LoadTasksCallback {
                    override fun onTasksLoaded(tasks: List<Task>) {
                        refreshCache(tasks)
                        callback.onTasksLoaded(ArrayList(cachedTasks.values))
                    }
    
                    override fun onDataNotAvailable() {
                        getTasksFromRemoteDataSource(callback)
                    }
                })
            }
        }
    
        override fun saveTask(task: Task) {
            // Do in memory cache update to keep the app UI up to date
            cacheAndPerform(task) {
                tasksRemoteDataSource.saveTask(it)
                tasksLocalDataSource.saveTask(it)
            }
        }
    
        override fun completeTask(task: Task) {
            // Do in memory cache update to keep the app UI up to date
            cacheAndPerform(task) {
                it.isCompleted = true
                tasksRemoteDataSource.completeTask(it)
                tasksLocalDataSource.completeTask(it)
            }
        }
    
        override fun completeTask(taskId: String) {
            getTaskWithId(taskId)?.let {
                completeTask(it)
            }
        }
    
        override fun activateTask(task: Task) {
            // Do in memory cache update to keep the app UI up to date
            cacheAndPerform(task) {
                it.isCompleted = false
                tasksRemoteDataSource.activateTask(it)
                tasksLocalDataSource.activateTask(it)
            }
        }
    
        override fun activateTask(taskId: String) {
            getTaskWithId(taskId)?.let {
                activateTask(it)
            }
        }
    
        override fun clearCompletedTasks() {
            tasksRemoteDataSource.clearCompletedTasks()
            tasksLocalDataSource.clearCompletedTasks()
    
            cachedTasks = cachedTasks.filterValues {
                !it.isCompleted
            } as LinkedHashMap<String, Task>
        }
    
        /**
         * Gets tasks from local data source (sqlite) unless the table is new or empty. In that case it
         * uses the network data source. This is done to simplify the sample.
         *
         *
         * Note: [GetTaskCallback.onDataNotAvailable] is fired if both data sources fail to
         * get the data.
         */
        override fun getTask(taskId: String, callback: TasksDataSource.GetTaskCallback) {
            val taskInCache = getTaskWithId(taskId)
    
            // Respond immediately with cache if available
            if (taskInCache != null) {
                callback.onTaskLoaded(taskInCache)
                return
            }
    
            // Load from server/persisted if needed.
    
            // Is the task in the local data source? If not, query the network.
            tasksLocalDataSource.getTask(taskId, object : TasksDataSource.GetTaskCallback {
                override fun onTaskLoaded(task: Task) {
                    // Do in memory cache update to keep the app UI up to date
                    cacheAndPerform(task) {
                        callback.onTaskLoaded(it)
                    }
                }
    
                override fun onDataNotAvailable() {
                    tasksRemoteDataSource.getTask(taskId, object : TasksDataSource.GetTaskCallback {
                        override fun onTaskLoaded(task: Task) {
                            // Do in memory cache update to keep the app UI up to date
                            cacheAndPerform(task) {
                                callback.onTaskLoaded(it)
                            }
                        }
    
                        override fun onDataNotAvailable() {
                            callback.onDataNotAvailable()
                        }
                    })
                }
            })
        }
    
        override fun refreshTasks() {
            cacheIsDirty = true
        }
    
        override fun deleteAllTasks() {
            tasksRemoteDataSource.deleteAllTasks()
            tasksLocalDataSource.deleteAllTasks()
            cachedTasks.clear()
        }
    
        override fun deleteTask(taskId: String) {
            tasksRemoteDataSource.deleteTask(taskId)
            tasksLocalDataSource.deleteTask(taskId)
            cachedTasks.remove(taskId)
        }
    
        private fun getTasksFromRemoteDataSource(callback: TasksDataSource.LoadTasksCallback) {
            tasksRemoteDataSource.getTasks(object : TasksDataSource.LoadTasksCallback {
                override fun onTasksLoaded(tasks: List<Task>) {
                    refreshCache(tasks)
                    refreshLocalDataSource(tasks)
                    callback.onTasksLoaded(ArrayList(cachedTasks.values))
                }
    
                override fun onDataNotAvailable() {
                    callback.onDataNotAvailable()
                }
            })
        }
    
        private fun refreshCache(tasks: List<Task>) {
            cachedTasks.clear()
            tasks.forEach {
                cacheAndPerform(it) {}
            }
            cacheIsDirty = false
        }
    
        private fun refreshLocalDataSource(tasks: List<Task>) {
            tasksLocalDataSource.deleteAllTasks()
            for (task in tasks) {
                tasksLocalDataSource.saveTask(task)
            }
        }
    
        private fun getTaskWithId(id: String) = cachedTasks[id]
    
        private inline fun cacheAndPerform(task: Task, perform: (Task) -> Unit) {
            val cachedTask = Task(task.title, task.description, task.id).apply {
                isCompleted = task.isCompleted
            }
            cachedTasks.put(cachedTask.id, cachedTask)
            perform(cachedTask)
        }
    
        companion object {
    
            private var INSTANCE: TasksRepository? = null
    
            /**
             * Returns the single instance of this class, creating it if necessary.
    
             * @param tasksRemoteDataSource the backend data source
             * *
             * @param tasksLocalDataSource  the device storage data source
             * *
             * @return the [TasksRepository] instance
             */
            @JvmStatic fun getInstance(tasksRemoteDataSource: TasksDataSource,
                    tasksLocalDataSource: TasksDataSource) =
                    INSTANCE ?: synchronized(TasksRepository::class.java) {
                        INSTANCE ?: TasksRepository(tasksRemoteDataSource, tasksLocalDataSource)
                                .also { INSTANCE = it }
                    }
    
    
            /**
             * Used to force [getInstance] to create a new instance
             * next time it's called.
             */
            @JvmStatic fun destroyInstance() {
                INSTANCE = null
            }
        }
    }
    

0 个答案:

没有答案