任何一种网站的功能只是前端(front end)或者视图(view)访问相应的模型(model)获取数据的一种方式。任何情况下,总会有模型和视图,真正改变的是模型和视图的连接方式。连接方式主要有两种:Controller 和 ViewModel,每种连接方式都有自己的优缺点。
MVC: Model-View-Controller
MVC模式最初生根于服务器端的Web开发,后来渐渐能够胜任客户端Web开发,能够满足其复杂性和丰富性。
MVC 在服务器端的表现为:
- Model: 模型(用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法)
- View: 视图(渲染页面)
- Controller: 控制器(M和V之间的连接器,用于控制应用程序的流程,及页面的业务逻辑)
MVC 的思想就是 Controller 负责将 Model 的数据用 View 显示出来,换句话说就是在Controller里面把Model的数据赋值给View。MVC 设计模式中视图和模型不需要有联系,因此,MVC模式允许开发人员在 Web 应用程序的不同组件上同时工作而不会相互影响。
但是 MVC 也有一些缺点。其中每个 Model 都有对应的 Controller,当应用程序扩展得更大并演变成具有许多相关模型时,所使用的控制器数量必须同步增长。这与大多数框架带来的新抽象层的自然引入相结合,创建了一个变得非常难以浏览的代码库。
iOS 中的 MVC:
MVVM: Model-View-ViewModel
MVVM 设计模式主要用于 Web 上的 single page/function applications。
我们需要数据所以有了M,我们需要界面所以有了V,而我们需要找一个地方把M赋值给V来显示,所以有了C,然而我们忽略了一个很重要的操作:数据解析。在MVC出生的年代,手机APP的数据往往都比较简单,没有现在那么复杂,所以那时的数据解析很可能一步就解决了,所以既然有这样一个问题要处理,而面向对象的思想就是用类和对象来解决问题,显然V和M早就被定义死了,它们都不应该处理“解析数据”的问题,理所应当的,“解析数据”这个问题就交给C来完成了。而现在的手机App功能越来越复杂,数据结构也越来越复杂,所以数据解析也就没那么简单了。如果我们继续按照MVC的设计思路,将数据解析的部分放到了Controller里面,那么Controller就将变得相当臃肿。还有相当重要的一点:Controller被设计出来并不是处理数据解析的。1、管理自己的生命周期;2、处理Controller之间的跳转;3、实现Controller容器。这里面根本没有“数据解析”这一项,所以显然,数据解析也不应该由Controller来完成。那么我们的MVC中,M、V、C都不应该处理数据解析,那么由谁来呢?这个问题实际上在面向对象的时候相当好回答:既然目前没有类能够处理这个问题,那么就创建一个新的类出来解决不就好了?所以我们就专门为数据解析创建出了一个新的类:ViewModel。这就是MVVM的诞生。
因为 Controller 只需要数据解析的结果而不关心过程,所以就相当于VM把“如何解析Model”给封装起来了,C甚至根本就不需要知道M的存在就能把工作做好,前提它需要持有一个VM。那么我们MVVM中的持有关系就是:C持有VM,VM持有M。
MVVM 四层结构:
- Model 层:模型是指代表真实状态内容的领域模型(面向对象),或指代表内容的数据访问层(以数据为中心)。
- Controller 层:实现业务逻辑,数据的增删改查。在MVVM模式中一般把C层算在M层中。
- ViewModel 层:视图模型是暴露公共属性和命令的视图的抽象。MVVM没有MVC模式的控制器,也没有MVP模式的presenter,有的是一个绑定器。在视图模型中,绑定器在视图和数据绑定器之间进行通信。
- View 层:将ViewModel通过特定的GUI展示出来,并在GUI控件上绑定视图交互事件,View 一般由MVVM框架自动生成在浏览器中。
- 绑定器:声明性数据和命令绑定隐含在MVVM模式中。在Microsoft解决方案堆中,绑定器是一种名为XAML的标记语言。绑定器使开发人员免于被迫编写样板式逻辑来同步视图模型和视图。在微软的堆之外实现时,声明性数据绑定技术的出现是实现该模式的一个关键因素。
MVVM 在 React 中对应关系:
- Model:对应组件的方法或生命周期函数中实现的业务逻辑和this.state中保存的本地数据,如果React集成了redux +react-redux,那么组件中的业务逻辑和本地数据可以完全被解耦出来单独存放当做M层,如业务逻辑放在Reducer和Action中。
- ViewModel:对应组件中的JSX,它实质上是Virtual DOM的语法糖。React负责维护 Virtual DOM以及对其进行diff运算,而React-dom 会把Virtual DOM渲染成浏览器中的真实DOM。
- View:对应框架在浏览器中基于虚拟DOM生成的真实DOM(并不需要我们自己书写)以及我们书写的CSS。
- 绑定器:对应JSX中的命令以及绑定的数据,如className={ this.props.xxx }、{this.props.xxx} 等等。
MVVM 的双向绑和单向绑区别:
- 一般,只有UI表单控件才存在双向数据绑定,非UI表单控件只有单向数据绑定。
- 单向数据绑定是指:Model 的变化可以自动更新到 View,但 View 的变化需要手动更新到Model。(通过给表单控件设置事件监听)
- 双向数据绑定是指念:Model 的变化可以自动更新到View,View 的变化也可以自动更新到Model。
- 双向绑定 = 单向绑定 + UI事件监听。双向和单向只不过是框架封装程度上的差异,本质上两者是可以相互转换的。
- 优缺点:在表单交互较多的情况下,单向数据绑定的优点是数据更易于跟踪管理和维护,缺点是代码量较多比较啰嗦,双向数据绑定的优缺点和单向绑定正好相反。
三大框架的异同:
- 三大框架都是数据驱动型的框架
- vue及angular是双向数据绑定;react是单向数据绑定。React使用的也是Object.defineProperty监控数据,只是没有进一步把表单控件的事件封装进v-model
- Vuex、Redux都是单项数据绑定的,即M的变化可以自动更新到V,但V的变化必须手动触发事件更新到M,这种单项数据绑定使数据更易于跟踪管理和维护。
- vue适用于构建快速轻量级的web应用,它具有更快的渲染速度和更小的体积。
- React伟大之处就在于,提出了Virtual Dom这种新颖的思路,并且这种思路衍生出了React Native,有可能会统一Web/Native开发。在性能方面,由于运用了Virtual Dom技术,Reactjs只在调用setState的时候会更新dom,而且还是先更新Virtual Dom,然后和实际Dom比较,最后再更新实际Dom。这个过程比起Angularjs的bind方式来说,一是更新dom的次数少,二是更新dom的内容少,速度肯定快。ReactJS更关注UI的组件化。
- React Native生成的App不是运行在WebView上,而是系统原生的UI,React通过jsx生成系统原生的UI,iOS和Android的React UI组件还是比较相似的,大量代码可以复用。