关于 Model 层的几点思考(一)

栏目: 编程工具 · 发布时间: 5年前

内容简介:Android 开发过程中,Model 层通常是比较薄弱的。获取数据的代码经过各种优秀的封装,已经可以简化到短短几行代码,对于简单的项目而言,全都写在 Activity/Fragment 中就是最合适的了,如果使用了 MVP 或者 MVVM 模式,也基本会把数据的获取放在 Presenter/ViewModel 中。(后面用业务逻辑层表示 Controller/Presenter/ViewModel)但 Model 层是很重要的,MVC,MVP,MVVM 甚至更复杂的架构模式,都需要 Model 层。最近为

Android 开发过程中,Model 层通常是比较薄弱的。获取数据的代码经过各种优秀的封装,已经可以简化到短短几行代码,对于简单的项目而言,全都写在 Activity/Fragment 中就是最合适的了,如果使用了 MVP 或者 MVVM 模式,也基本会把数据的获取放在 Presenter/ViewModel 中。(后面用业务逻辑层表示 Controller/Presenter/ViewModel)

但 Model 层是很重要的,MVC,MVP,MVVM 甚至更复杂的架构模式,都需要 Model 层。最近为了做接口数据格式的自动化测试,又对 Model 层的实现进行了一次学习,本文记录了学习过程中的一些问题以及个人理解。问题如下:

  • 为什么数据获取不应该写在业务逻辑里?
  • Model 层应该包括什么内容?
  • 如何构造 Model 层?
  • 如何以 Model 为界线,分别对业务层和数据层做自动化测试?

问题一:为什么数据获取不应该写在业务逻辑里?

说来惭愧,之前写过的代码都是在业务里做网络请求,处理回调数据。这种方法存在几个问题:

  1. 多个页面请求同一接口时,处理代码会重复
  2. 添加数据缓存功能会影响业务代码
  3. 无法进行单元测试

而独立出 Model 层可以解决上述问题,使代码更易读且便于扩展,还能添加单元测试提高软件质量,对于 App 的长期发展有很大的好处。

问题二:Model 层应该包括什么内容?

  1. 数据获取的方法:包括网络请求和读取本地文件、数据库等
  2. 数据处理的方法:Model 层提供的数据应该是业务中直接可用的,这样就能在测试中区分开错误的来源是数据还是逻辑 bug
  3. 实体类

问题三:如何构造 Model 层?

终于到了写代码的时间,这次参考的依然是 googlesamples/android-architecture 。为了满足单元测试的需求,我将一个 demo 项目重构为 MVP 模式了。

Model 层内部还需要再分层,将不同来源(网络和本地)的数据获取代码分开。代码的结构大概这样:

关于 Model 层的几点思考(一)

业务层需要的数据获取定义成 DataSource 接口中的函数,固定参数和回调。具体实现为 LocalDataSource 和 RemoteDataSource 等。Repository 实现 DataSource 并持有具体的一种或多种 DataSource,通过组合不同的 DataSource 实现获取数据的功能。

举个栗子:

某 App 首页需要通过网络获取一个列表数据来展示,为了更好的用户体验,每次刷新的列表会缓存在本地。这样在请求成功前就不是空白的页面了。

interface ExDataSource {
    interface LoadListCallback{
        fun onSuccess(list: ArrayList<ListItemBean>)
        fun onError(errorCode: Int, errorMsg: String)
    }

    fun loadList(page: Int, callback: LoadListCallback)
}

复制代码

然后分别实现具体的数据获取方法:

// 对数据处理的函数可以以静态方法的方式提到外面
class ExRemoteDataSource: ExDataSource{
    override fun loadList(page: Int, callback: LoadListCallback){
        // 发起网络请求,解析返回数据,如果不能解析成ArrayList<ListItemBean>也回调失败
        // 具体代码实现与网络请求框架有关,此处不放代码了
    }
}
···

class ExLocalDataSource: ExDataSource{
    override fun loadList(page: Int, callback: LoadListCallback){
        // 从数据库或者文件获取缓存的数据
    }
    
    fun setCacheList(list: ArrayList<ListItemBean>){
        // 更新缓存内容
    }
}
复制代码

最后在 Repository 中处理缓存逻辑:

//
class ExRepositiry(
    private val remoteDataSource: ExRemoteDataSource,
    private val localDataSource: ExLocalDataSource
): ExDataSource {
    
    override fun loadList(page: Int, callback: LoadListCallback){
        //具体如何使用缓存跟需求有关,这里简化写一下 
        // 先加载本地数据做显示
        localDataSource.loadList(page, callback)
        
        // 同时发起网络请求
        remoteDataSource.loadList(page, object: LoadListCallback{
            override fun onSuccess(list: ArrayList<ListItemBean>){
                // 成功后更新缓存,刷新页面 
                localDataSource.setCacheList(list)
                callback.onSuccess(list)
            }
            override fun onError(errorCode: Int, errorMsg: String){
                callback.onError(errorCode, errorMsg)
            }
        })
    }
}

复制代码

业务层只需要创建 Repository 就能获得想要的数据了,对于错误的情况,就详细规划 onError 的回调,再根据具体需求处理。

  • 问题3.1:如何避免创建大量回调接口?

接口回调是无法从根本上取代的,如果为了代码简明,可以创建几个泛型接口模板来避免每个请求对应一个接口。使用 Kotlin 的话可以直接按成功和失败传入函数:

···
    fun loadList(
        page: Int, 
        onSuccess: (ArrayList<ListItemBean>) -> Unit, 
        onError: (errorCode: Int, errorMsg: String) -> Unit
    )
···
复制代码
  • 问题3.2:如何划分 Repository?

随着项目的发展,需要的数据会越来越多,都写在同一个 Repository 中获取数据会让代码的可读性下降。应该按照业务将 Repository 模块化,以适应未来项目的模块化和组件化。(不需要分得太细碎,Repository 本身由多个独立的数据获取代码构成,即使有很多行也能保证逻辑清晰)

问题四:如何以 Model 为界线,分别对业务层和数据层做自动化测试?

算了一下内容,再写下去就太长了。而且关于单元测试的部分还没应用到项目中,不确定还有没有坑,最后这个问题下周单独写一篇吧。

总结

Model 层可以说是欠了很久的技术债了,最初觉得只是几行代码的网络请求拆出来也没有意义,随着业务的发展,出现了很多需要缓存的页面,就也把取本地的数据的代码写在业务逻辑中了。现在要保证复杂逻辑代码的稳定性,想要添加单元测试,再回头看代码才明白已经走偏了太多。

代码的架构应该是分层,而不是分块。很多代码中把一部分业务逻辑委托到一个 xxManager 去做,表面上似乎单个文件中的代码少了,但并不符合单一职责原则,实际上代码的可读性还是不好,后续维护也依然麻烦。

从事 Android App 开发快 2 年了,我竟然还没写过单元测试,其实是很无奈的一件事。不写测试的理由可能有很多,但写单元测试的理由只有为了更高的代码质量。为了让代码能够长期维护下去,解耦和单元测试都是非常重要的。

那么你开始写单元测试了吗?


以上所述就是小编给大家介绍的《关于 Model 层的几点思考(一)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

第三次浪潮

第三次浪潮

[美]阿尔文·托夫勒 / 黄明坚 / 中信出版集团 / 2018-7 / 79.00元

《第三次浪潮》是美国著名未来学家阿尔文•托夫勒的代表作之一。1980年出版之际,随即引起全球热评,堪称中国改革开放的指南。本书阐述了由科学技术发展引起的社会各方面的变化与趋势。托夫勒认为,人类迄今为止已经经历了两次浪潮文明的洗礼:第一次是农业革命,人类就此从原始渔猎时代进入以农业为基础的文明社会,并历经千年,直到工业革命的到来。随后,人类社会历时300年摧毁了落后的第一次浪潮文明,并在“二战”后1......一起来看看 《第三次浪潮》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

随机密码生成器
随机密码生成器

多种字符组合密码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换