自己理解前端MV*

写在前面

笔者第一次接触MVC是在java中,不是ssh之类的大家伙,只是单纯的分层开发,为了代码结构更清晰

  • V(View)在java中可以是swt, swing做出的GUI,当然,也可以是jsp生成的页面

    View是单纯的界面,负责以友好的形式展示数据给用户

  • M(Model)可以是纯粹的Java Bean(傻豆豆,只有自定义数据结构和getter/setter),也可以带点数据校验逻辑

    还有把数据校验逻辑放在V或者C里面的,取决于具体场景,比如jsp应用把数据校验逻辑放在V里比较合适,可以减少请求

  • C(Controller)是业务逻辑聚集的一层,所有重要业务逻辑都在C里面

    C负责接收V传过来的用户输入,处理完毕后更新M,M再通知V更新,可以一个V对应(依赖)一个C,也可以多个V对应1个C(多个页面的业务逻辑基本相同的话),但1个V不应该对应多个C,因为这种依赖关系就是紧耦合了;M和V的对应关系取决于实现方式,是经典观察者模式还是发布/订阅模式,前者M直接通知V更新,后者M只能通过C更新V

后来发现有些逻辑放哪里都不合适,比如数据库操作(放C里?)、配置数据/常量(放V里?),于是新增了Core放常量、DAO层放数据库操作,都算C的辅助层

MVP和MVVM的理念与这个不同,不是多一层少一层,而是对层的职能做了重新划分,当然,重新划分之后也添了其它辅助层

一.MVC

从输入到输出,数据流(勉强算数据流图吧,阮把这个叫通信方式图)如下:

MVC数据流

MVC数据流

注意:不是依赖图。因为从依赖关系上看,M和V是观察者模式关系,应该是V依赖M(Observer知道Subject的存在及其公开的接口),M不依赖V(Subject不知道谁关注了它,也不在乎都是些谁)。而从交互关系(数据流)上看,M更新了V(Subject变了,会自动通知所有Observer),V没有办法直接更新M。

依赖关系取决于具体实现,个人认为去纠结Trygve Reenskaug最初的实现没有任何意义,所以依赖关系图是画不出来的,而且多年以后上面的数据流图可能也是错的,从最初的C接收用户输入,到现在的V也能接收,以后的变化谁知道呢?

(八卦:这也就是winter和阮的分歧所在,阮眼中的MVC是广义的,是一种分层思想;而winter认为MVC就是79年的东西,其它的通通不能算MVC。。。两篇博文在底部参考资料中都列出来了,有兴趣可以去瞅瞅)

(题外话:1979年Trygve Reenskaug提出了MVC,这个据说是正版,当时用户输入只能由C获取,V的功能及其弱,连输入框上的光标都是C控制V绘制的,所以规定C只能存在一个,所有逻辑都必须流经C,便于控制繁琐的界面展示。而现在用户输入可以由V直接获取,绘制光标等工作由操作系统自动完成,再拘泥于C只能存在一个就是彻头彻尾的傻了)

Backbone.js

backbone是前端MVC的框架范例,提供了MVC实现以及基本工具,自由度很大,实际应用中需要组合其它工具,比如underscore、jQuery/zepto是必需品

Backbone是脊椎,表示只提供了最关键的框架实现,其余部分都是非常自由的,关于Backbone的更多信息,请查看底部参考资料

二.MVP

最初的MVP图示如下:

mvp

mvp

与MVC相比,最大的区别不是C改名成P(Presenter)了,也不是多的一条M到V的线,等下,不是观察者模式吗?怎么M能直接访问V了(Subject能直接访问Observer了)?待会儿再议。最重要的区别是P不是单一的对象,而是图中的interactor, command以及selection合起来叫做P,也就是说P是不存在的,P被分解成“interactor, command以及selection”了

因为在本来M和V的观察者关系下,V无法直接访问M,只能靠C传递,用着不爽(可能是效率或者易用性上的不爽),然后决定增强V,让V可以直接访问M(V能接收用户输入也算是增强,因为最初的MVC只有C能接收用户输入,用户在直接和C交互,光标、输入文字什么的都是C控制V显示的)。然后把C改名为P,以区别MVC,其实叫M(胖V)C也行,V变厚了,C就变薄了(简单的数据显示交给V了,直接获取M的数据显示出来(数据与视图绑定?),当然,从上图可以看出V只能读M,写还是要通过C的),所以有人说P是一种C,确切地说是更薄的C

MVP没有合适的范例框架,因为大家对MVP的理解存在争议。有的文章说P是增强的V,还有说P里面放的都是展示逻辑。。。那么业务逻辑放哪里?不能单单从Presenter字面意思上理解,想当然地去解释

(MVP是1996年提出的,因为有人觉得1979年的MVC已经不合适了,MVC的理念当然还存在,只是最初死板的规则,比如C只有一个,只有C能获取用户输入等观念已经过时了,MVP本身可能也只是过渡的产物,有用的只是背后的理念,比如分层开发、模块化、事件驱动等等)

三.MVVM

MVVM是微软推出WPF时提出的模式,WPF的特点是强大的控件,比如DataGrid可以直接与数据表绑定,极大地减少了简单数据表展示的工作量。wpf的View是用XAML定义的,控件的基本功能,比如输入数据校验,通过简单的XAML配置就可以实现了,这其实就是MVVM最大的特点:V与M的双向绑定

MVVM的好处是把V进一步分离,甚至V是用另一种语言(XAML)描述的,这样就极大地增强了控件的可复用性,直接把上一个项目里自定义控件的XAML代码拿过来就可以用,而不用从原项目小心翼翼地剥离逻辑代码

winter给出的图示如下:

mvvm

mvvm

也就是说,MVVM里的V是一个很强大、很完善、很厚的V,因为这个V = V+ C + E。至于数据绑定,从使用的角度看是V和M绑定了,比如TextBox的值会自动与Model数据同步。从上图看是V和VM之间的数据绑定,VM可以通过“命令”来操作V,比如xx.close()之类的,更详细的解释如下:

如何呈現是view的事,調用方只用給view一個data,view就只負責這個data的顯示,調用者不用管view如何顯示,只負責將data傳遞,view也不用管數據從何而來,只要將data以自己的方式呈現,并且時刻關注data的變化如何反映到view上來就好。

而雙向綁定,則是一個附加產品,畢竟只有像textbox,form等會改變數據的UI不多,大部分UI都只是單向的呈現數據而已。不過有雙向綁定在,則可以將view和調用方分離得更徹底,即獲取數據不必在意特別的view,如一個日期是用戶在textbox中輸入,還是用calendar選取的無關緊要,因為那是view設計和安排的事。

Angular.js

Angular的MVVM几乎是公认的,MVVM的特点就是重,wpf好用是因为提供了一整套强大的常用控件,可想而知

关于Angular的更多信息请查看Angular官网,Angular是Google做的,或许是MVC的发展方向

四.MV*框架的选择

不建议直接将业务库框架直接取来使用,更不建议使用过重的业务框架,最好是能明白框架想要解决的问题,与自己项目的实际需求,自己造轮子知根知底。

(引自浅谈移动前端的最佳实践

这句话应该很在理,有创业公司的朋友说公司要求用Angular,没有调研,没有讨论,就是要用。为什么?火呗,合适不合适好用不好用都不重要

自己的内部框架当然是量体裁衣,出了问题有人去解决,不用去搜寻解决方案、不好用可以自己改,改得好可以直接扩展进去、嫌太大可以清理一下,把不常用的部分提出来作为可选模块。。。自己的肯定要比别人的用着舒服,哪里不爽改哪里,比如$()的问题,应该根据业务情景好好选选,看document.querySelector能否满足需求,不行再看zepto的兼容性够不够,实在不行才用jQuery

五.为什么要了解MV*

更糟糕的是,今天无数经过演绎的MVC实现(如backbone)和科普文,要么是原本作者概念已经很混乱,掺杂私货,要么为了适配现代的标记语言和控件模式,自己修改了经典MVC中的一些概念和耦合关系。实际上今天MVC已经没法作为一种交流的标准词汇了。

花时间了解MV*就是为了能够听懂别人在说什么,但如上面所说,MVC已经不是同行间能秒懂的那种标准词汇了,对与错可能不重要,如果非要纠结就得去读N篇论文,找到MV*最初的实现理念,但没必要这样做了,因为winter帮我们做过了,最初的实现是一个参照点,接触其它MV*实现时可以对比理解,但不要纠结对错,好用实用就行

参考资料

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

code