MVC与MVVM

作者: 红烧那个鱼丶 | 来源:发表于2017-10-25 11:19 被阅读93次

    从MVVM到RxSwift

    最近一段时间正在研究响应式编程,目前iOS开发中用的比较多的响应式编程框架有ReactiveCocoaRxSwift两种。我在学习RxSwift使用的过程中发现,关于该框架的文章大多比较晦涩,内容大多偏向于框架原理,在结合MVVM设计模式使用上却没有过多深入。本篇抛砖引玉,从MVVM解决的问题开始,逐步讲到如何将RxSwift结合MVVM使用到实际开发中。


    MVC与MVVM

    说MVC框架不好用是没有用好MVC框架
    但是MVVM会让复杂工程的构架变得更加简单直观

    MVC和MVVM其实之间并没有优劣之分,只是适用的场景不同。一门技术的出现必定是为了解决一类问题,抛开开发场景谈框架优劣就是耍流氓。


    MVC解决的问题

    比如,我们须要开发一个完整功能的软件,它会包含:

    • 获取数据(网络请求,数据库读取,本地文件读取)
    • 初始化并加载和配置视图
    • 将获取的数据展示到视图上
    • 将变更的数据反馈给数据库

    假如没有MVC或者我偏不使用任何设计模式,将所有流程全部写在Controller中 我真是哔了狗才会这么做 ,进行编程我会怎么做:

    • 写若干个获取数据(网络请求等)的方法
    • 逐一初始化并配置UIKit库给定的视图控件
    • 使用得到的Dictionary或者Array对控件逐一赋值
    • 获取TextField的文字,Switch上的Bool值,并组装成格式化的数据上传或者存储

    这样的代码会出现什么问题:

    • 这个文件中的代码会轻易超过1500行(代码难以阅读)
    • 产品说辛苦大家一下我们要改个小需求,于是我加了三天班;UI说亲爱的我想变一下页面布局,于是我又加了三天班(代码难以修改)
    • 有个视图一样但是逻辑不同的需求,我只好从源代码复制粘贴加以修改重新实现(代码难以移植)
    • 出现了一个了不得的BUG,我再加三天班(代码难以维护)
    • 我由于加班劳累过度住院了,接手该项目的程序员在看了代码之后立即递交了辞职报告(代码难以交接)

    这种将所有代码放在一起的写法违背了程序设计时最基本的思想:高内聚,低耦合
    所以MVC的出现就是为了写出模块化的程序,将模块之间的耦合降低,模块与模块的联系通过简单的接口进行暴露,Model只处理数据部分,View只处理视图部分,他们两部分在Ctroller中相互发生联系。
    在Controller中规定Model何时初始化、何时赋值给View进行展示的逻辑,叫做 业务逻辑


    MVC无法解决的问题及MVVM

    MVC的构架能够解决目前软件设计的绝大部分问题。
    但是遇见一个功能复杂,业务逻辑繁琐的功能,即便MVC已经将它拆分成Model-View-Ctroller三部分,但Controller中的代码仍然会轻易超过800行。
    所以,为了 高内聚,低耦合 ,为了代码更容易维护和修改,为了不加班, 我们需要对功能进行进一步拆分。将功能拆分为: <center>数据模型 -- 视图 -- 视图控制器 -- 业务逻辑</center>
    正式因为页面业务逻辑太复杂,才使得MVC中的Ctroller过于厚重,所以我们要将业务逻辑拆分出来进行单独处理
    所以MVVM这种在MVC基础上的设计模式应运而生。

    MVC与MVVM之间最大的区别在于,MVC中用于管理业务逻辑的是Controller,MVVM中用于管理业务逻辑的是ViewModel。从MVC到MVVM实际上就是把MVC中Ctroller管理的业务逻辑拆分出来到ViewModel中。

    如果要弄明白如何将业务逻辑拆分出来,就要先弄明白业务逻辑在代码中是以什么方式存在的,业务逻辑之于服务器是什么关系,业务逻辑之于视图是什么关系。


    应用之于服务器的关系:什么是业务逻辑

    服务器之于应用的关系:

    1. 传递数据给应用
    2. 接收并处理,应用传入的数据及事件
    3. 告诉应用什么时候启动什么事件

    前两个都很好理解,这是我们写程序时的日常工作。第三个‘告诉应用什么时候该启动什么事件’都是指哪些呢:

    • 基于HTTP/HTTPS响应的服务器,会告诉应用,网络请求的成功状态及请求结果
    • 基于TCP/UDP长链接的服务器会将事件发送给应用,应用在客户端给出对应的状态

    简化一下就是:

    服务端在 某一时刻 将数据传递给应用,客户端将 数据转化为状态 展示给用户
    客户端在 某一时刻 从视图 接收到用户状态 ,并转化为数据提交给服务器

    数据是由Model处理的。那么 状态和时间的处理,就是业务逻辑


    ViewMode与View的关系

    既然业务逻辑需要处理时间和状态,并展示到视图上;同时,视图需要向业务逻辑告知自己的状态更新,因为这些状态要被转化成数据提交到服务器。
    简化一下就是:

    View需要调用VM的某些功能
    VM也需要调用View的某些功能

    这种双向操作一般我们会使用delegate或者block
    其实在MVVM中使用这两种方式实现互绑也未尝不可,只不过有些麻烦,因为他们都是在ViewController中创建的,所以使用这两种方式的话,我们需要定义一个XXViewDelegate和一个XXControllerDelegate,或者使用定义block,然后将block相互赋值,或者我们可以使用Notification...

    上边的都是废话

    这种双向关系使ViewModel好像View的一个映射,可以通过ViewModel获取到View的状态,也可以通过操作ViewModel操作View

    这种相互响应的关系其实就是响应式关系

    我们可以通过ReactiveCocoa框架或者RxSwift框架使View和VM之间快速建立起这种关系。

    *注:那些不关乎业务逻辑的视图状态,比如动画效果等,交给视图自身去管理。


    两种构架在工程中的应用原则

    归根结低还是开头的那一句话:

    说MVC框架不好用是没有用好MVC框架
    但是MVVM会让复杂工程的构架变得更加简单直观

    在同一个工程中MVC和MVVM可以混合使用,在实际客户端开发中,如何选择一个合适的构架给功能,关系到功能的开发成本,复杂度,可维护性和可移植性,设计模式的选择其实就是在这几个方面做权衡。
    一般遵循的原则是:

    工程第一,构架第二,代码第三

    工程第一:开发时需要保证代码按期提交,不延误工程进度,且bug率低。如果时间紧张,就需要选择自己熟悉的构架来提高开发效率,尽管这套框架不是最适合这个工程的,但是工程进度比合适的构架要重要。
    构架第二:在保证工程能按期完成的情况下,需要有一套合适的构架来提升工程的可维护性和可移植性。
    代码第三:这是一个人的习惯问题,是一个程序员每时每刻都需要规范的行为,几乎是一种无意识行为,如何使命名变量及方法名称让代码更具有可读性,如何写注释让维护者或者将来自己维护代码更能理解编写意图。这种习惯需要时刻培养,却不能急于求成。毕竟,完成工程是眼前的事,写出的代码优不优雅,是一辈子的事。

    相关文章

      网友评论

        本文标题:MVC与MVVM

        本文链接:https://www.haomeiwen.com/subject/ioqqpxtx.html