关于网络层的设计(一)——和业务层的对接

前言

关于网络层的设计,最主要的是和业务层的对接问题。
网络层设计得好,可以让业务层开发事半功倍;反之,若网络层设计地很糟糕,则会让业务层开发事倍功半,心里法克连连。


988593-f3d83edda7f71cf1

关于网络层和业务层的对接,我们一般从下面几个方面进行考量:

  • 选择哪种方式请求网络数据,系统自带的还是AFNetworking?
  • 以什么模式给业务层交付数据?delegate 还是block?
  • 交付给业务层什么形式的数据?直接返回dict就行了,还是把dict在网络层转换为ResultModel再交给业务层?
  • 封装API应该选择集约型还是离散型?

第一个问题,“选择哪种方式请求网络数据?”。第三方库AFNetworking很强大而且使用起来比较简单,所以一般我们选择AFNetworking。苹果自带的NSURLSession等以后再研究。

第二个问题,“以什么模式给业务层交付数据?”。一般选择Delegate和block。关于它们,应该说各有利弊吧,具体使用场景具体选择使用。block使用起来较方便,但也有调试时不好追踪,容易出现循环引用等坑的缺点。而且若在业务层block返回数据后,要做比较复杂的逻辑处理的话,那在block里会写有大段代码,这样阅读起来也不好,使代码整体结构显得很不清晰。
但是,在此,我们仍先以block为例来理解网络层的设计。

第三个问题,“交付给业务层什么形式的数据?”。我们设计网络层,就要想着能尽量减轻业务层的开发量,最好把网络层从后台拿到的一大串数据,剥离、加工、整理成业务层需要的数据格式然后再交付给它。

第四个问题,“封装API应该选择集约型还是离散型?”。所谓集约型,就是只能业务层提供一个方法,所有业务层的网络请求都要通过该方法完成。因此,该方法至少要能传入接口路径(path)、请求方式(get/post)、请求参数(param)等。集约型的好处是对于网络层的编写来说方便快捷,但对业务层来说要传入这么多参数并不太好。我们设计的目的就是尽量使业务层使用起来简单轻巧,所以我们常常采用离散型方式。(说得不太恰当。集约型为所有的业务请求提供一个接口,省去了编写业务模块xxxManager的工作量。但对集约型而言,提供的这个唯一的网络请求方法得有接口地址,请求方式,接口参数等多个参数。这是其繁琐之处,而离散型则为了避免给业务层带来这样的繁琐,而在xxxManager提供的接口方法里自己配置了接口地址interface和请求方式,并以方法名加以体现。那对业务层开发来说就简洁明了了许多。一个比如用户模块UserManager里的对登录请求的封装,只需业务层传入accountpassword两个参数,而接口地址和请求方式已封装在其方法里了login:password:success:failure,而且方法名也体现出了请求接口login。但离散型的问题是无疑为增加代码量,为编写xxxManager层将花费大量时间。)
不言而喻,和集约型相对的,离散型就是根据功能模块分为不同的模块,分别提供不同的方法给业务层调用。比如,把和用户有关的所有网络请求,放在一个叫UserManager的类中,登录、注册、修改密码等分别提供不同的方法,这样的好处在于,一、不同功能模块放在不同的文件中,使项目结构更清晰,维护升级更容易;二、对于业务开发人员来说,不同的功能叫不同的方法名这样更友好易懂。三、更重要的是,你可以在xxxManager这一层做一些针对该模块的个性化处理。没错,你可以在这一层完成上个问题中所说的数据加工后再交付给业务层。我们把和用户相关的网络请求API都定义在UserManager类中,并在其中转换为UserObject然后交付给业务层。
除此外,“离散”不仅体现在提供的API方法上,还体现在网络请求连接上。我们定义一个HttpClient类,在该类中专门完成对服务器的网络请求。并且给xxxManager这一层提供不同请求方式对应的方法。

好了,基本结构就是这样,下面上代码。我们“从内至外”的看代码。
首先就是HttpClient这个类了,该类是完成网络请求连接的核心。并给xxxManager提供网络连接的接口方法。

HttpClient.h

HttpClient.m
注意,我们提供给外部get和post请求对应的两个方法调用,但其实在内部,我们是定义了一个“全能方法”来完成网络连接的,这才是核心。

好了,现在看看xxxManager层。
UserManager.h

UserManager.m
登录、注册、修改密码、修改个人资料分别提供不同的方法。在相应方法里通过调用HttpClient提供的网络连接方法完成网络连接,然后把数据转换加工成业务层需要的数据格式UserObject,再交付之。

好了。当业务层开发人员需要完成“登录”功能时,只需调用UserManager中我们定义的login方法就得到了网络数据,并且已转为UserObject给我们。



补充和优化

上面我们实现了一个简单的网络层,但其实是比较简陋的。真是情况要考虑很多地方的。

1. 在请求中添加签名认证,保证请求来源于我们自己的APP。

2. 取消无用的请求。
比如,比如我们刚进入一个界面后,此刻便会发出一条该界面数据的请求,但是此时用户却点了“返回”,退回了上个界面。此时上个界面的请求已经飞出但还未完成。这时,我们应当取消上个界面的请求,释放带宽。这样对于下来的网络请求是有利的。

3. 错误信息的处理

这段代码,AFNetworking提供的GET请求,请求成功时回调block返回responseObject,失败时返回error。但是请注意,这里的错误回调仅仅指网络请求错误,要注意区分网络错误和业务错误(也就是网络请求是成功的,但是对于我们的业务来说,是有问题的)。这些信息同样是会在responseObject返回。实际上一般网络请求成功后,后台返回的responseObject一般都有errorCode字段,只有当errorCode=0时,就说明一切OK,正常返回了我们需要的数据。所以,为了给业务层提供方便,我们还得在网络层做些处理。使交付给业务层的数据里,成功回调的block里就纯粹了业务逻辑意义上正确的数据,而失败的回调里的数据则包括一切错误信息。所说的处理就是在该方法里对回调block做层包装。

4.多服务器多环境切换:
一般比较规范的项目都有开发环境、测试环境、预发布环境、正式环境(生产环境)四种环境,它们对应的服务器地址分别是不同的。在项目版本迭代过程以“开发——>测试——>预发布——>正式”这个顺序进行的。开发环境就是新需求下来后的更改。测试环境就是给测试打了包后,改bug时的更改。预发布环境就是测试基本完成,交付给运营测试,改动基本比较小。正式环境不用解释,不言而喻。
我们可以把多环境的配置写在预编译头文件中:

1 2 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部