-
Notifications
You must be signed in to change notification settings - Fork 312
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
界面之下:还原真实的MV*模式 #11
Comments
不错。其中 Model 2 的模式更多的是由C/S模式转变而来的吧,看起来象是把MVC硬套在C/S上。 |
感谢嘉华大大分享干货 :) |
赞 |
赞! |
我看到的另一种关于MVC的说法是Controller并不执行业务逻辑,它只负责简单的参数验证和指定哪个Model进行业务逻辑的执行,Model则执行相应的业务逻辑 |
@LuoPQ 那完全没有必要分一个controller出来了,全部交给model做就好了 |
@livoras controller里面只是负责参数验证,安全检测,如果充斥着各种各样的业务逻辑,感觉不太好,Model负责和自身相关的业务逻辑,这样不是更清晰吗 |
@LuoPQ 问题是,你这个Model如果用在别的地方,就会把一堆无关的业务逻辑带过去 |
写的很清晰 |
赞! |
awesome! |
MVC主要的业务逻辑在V,MVP主要的业务逻辑在P |
「Model层对应用程序的业务逻辑无知」如果这里的 Model 定义为 Domain Model,那他怎么会对应用程序的业务(Domain,领域)逻辑一无所知?这里的定义有出处吗? |
@LuoPQ 把 Controller 的职责定义为协作(路由、输入预处理等)而不涉及到具体业务逻辑,感觉更清晰一些 |
好文章,感谢作者,转载啦: https://linux.cn/article-6481-1.html |
Model: 负责更新自己和给view提供数据, 当modle数据变化时通知给他的观察者们。 View: 是Modle的观察者,当Modle数据变化时使用它的数据显示自己。View也封装了视图的细节(html/css/dom做操),通过Dom事件捕获界面上的用户行为,并且通知给他的观察者们。 Controller:是View的观察者,View把需要Controller处理用户行为通知给Controller, Controller 调用modle上的方法更新数据。 其中只有View了解视图的细节, Model和 Controller 对视图无感知。Model和View,Controller 和View 之间通过观察者模式交互。这样做的好处是,可以方便的对Conrtoller 和Model进行测试 |
赞! |
讲的真好,我还是喜欢MVC模式; |
你画图看上去真不错,是什么工具呢? |
@keenkit PPT |
赞! 好文章,感谢作者。。。 |
分析的不错 |
gulp运行出现错误:E:\jscode\test\MVW\MVW-demos-master\node_modules\gulp-browserify\node_modules\browserify\node_modules\browser-pack\node_modules\combine-source-map\node_modules\source-map\lib\source-map\array-set.js:83 |
我个人认为,在形容MVC三者时,最后不要带例如“Model层”这样的说法,因为“层”是一种带有严格意义上的上下级关系的,例如J2EE中的Controller层、Service层、Dao层。MVC架构模式中的C也不单指的Controller层,指的是仅仅是一种结构的控制器。 |
赞!!!很清晰的讲述了MV*,谢谢~~ |
smalltalk-80 的 mvc 的表述似乎不太对,用户应该是通过 controller 交互的,而不是 view。这是 wikpedia 上的解释: 到了 mvp,截获用户交互的就变成 view 了,这是和 mvc 的区别。 然后 mvc 移植到 web 上(model2)后,controller 的角色实际上变得非常像 mvp 中的 presenter(model 和 view 的中继者),但是我们并没有称为 web mvp,而是称为 web mvc,就是因为截获请求的是 controller,而不是 view。 |
好文 |
mark |
Speration of Duties-->Separation of Duties |
赞👍 |
必须赞一个,向前辈学习和看齐~ |
受益匪浅! |
赞 |
+1 |
职责分离(Speration of Duties)单词写错了 |
请问 应用逻辑和业务逻辑与什么区别 |
膜大佬,向大佬学习 |
@Brant-Ma 缘妙不可言 |
膜 |
Dijango -> Django |
值得多次阅读的文章,这次再看似乎又理解得深入了一点。 |
学习学习 |
好文, 看完之后终于明晰了一些,收藏了! |
感谢大佬分享 |
学到了orz |
大佬就是大佬4年前,就已经分析的这么透彻,其他文章各种原理分析,看了后还是相关概念还是比较模糊的,也分辨不出对与错,看了这篇后,能够具体的理解文章表达的深刻含义,舒服。orz |
"View和Model的同步消息是通过观察者模式进行,而同步操作是由View自己请求Model的数据然后对视图进行更新" ---- 对这点不太理解,都使用观察者模式了,为何Model在广播消息的时候不直接把数据推送过去,而非要view自己去获取呢,这是不是有些多余了? |
UPDATE(2015-10-29):更新MV*关于业务逻辑的描述,此处感谢 @LuoPQ @finian 指出错误
作者:戴嘉华
转载请注明出处并保留原文链接( #11 )和作者信息。
目录:
前言
做客户端开发、前端开发对MVC、MVP、MVVM这些名词不了解也应该大致听过,都是为了解决图形界面应用程序复杂性管理问题而产生的应用架构模式。网上很多文章关于这方面的讨论比较杂乱,各种MV模式之间的区别分不清,甚至有些描述都是错误的。本文追根溯源,从最经典的Smalltalk-80 MVC模式开始逐步还原图形界面之下最真实的MV模式。
GUI程序所面临的问题
图形界面的应用程序提供给用户可视化的操作界面,这个界面提供给数据和信息。用户输入行为(键盘,鼠标等)会执行一些应用逻辑,应用逻辑(application logic)可能会触发一定的业务逻辑(business logic)对应用程序数据的变更,数据的变更自然需要用户界面的同步变更以提供最准确的信息。例如用户对一个电子表格重新排序的操作,应用程序需要响应用户操作,对数据进行排序,然后需要同步到界面上。
在开发应用程序的时候,以求更好的管理应用程序的复杂性,基于**职责分离(Speration of Duties)**的思想都会对应用程序进行分层。在开发图形界面应用程序的时候,会把管理用户界面的层次称为View,应用程序的数据为Model(注意这里的Model指的是Domain Model,这个应用程序对需要解决的问题的数据抽象,不包含应用的状态,可以简单理解为对象)。Model提供数据操作的接口,执行相应的业务逻辑。
有了View和Model的分层,那么问题就来了:View如何同步Model的变更,View和Model之间如何粘合在一起。
带着这个问题开始探索MV模式,会发现这些模式之间的差异可以归纳为对这个问题处理的方式的不同。而几乎所有的MV模式都是经典的Smalltalk-80 MVC的修改版。
Smalltalk-80 MVC
历史背景
早在上个世纪70年代,美国的施乐公司(Xerox)的工程师研发了Smalltalk编程语言,并且开始用它编写图形界面的应用程序。而在Smalltalk-80这个版本的时候,一位叫Trygve Reenskaug的工程师设计了MVC图形应用程序的架构模式,极大地降低了图形应用程序的管理难度。而在四人帮(GoF)的设计模式当中并没有把MVC当做是设计模式,而仅仅是把它看成解决问题的一些类的集合。Smalltalk-80 MVC和GoF描述的MVC是最经典的MVC模式。
MVC的依赖关系
MVC出了把应用程序分成View、Model层,还额外的加了一个Controller层,它的职责为进行Model和View之间的协作(路由、输入预处理等)的应用逻辑(application logic);Model进行处理业务逻辑。Model、View、Controller三个层次的依赖关系如下:
Controller和View都依赖Model层,Controller和View可以互相依赖。在一些网上的资料Controller和View之间的依赖关系可能不一样,有些是单向依赖,有些是双向依赖,这个其实关系不大,后面会看到它们的依赖关系都是为了把处理用户行为触发的事件处理权交给Controller。
MVC的调用关系
用户的对View操作以后,View捕获到这个操作,会把处理的权利交移给Controller(Pass calls);Controller会对来自View数据进行预处理、决定调用哪个Model的接口;然后由Model执行相关的业务逻辑;当Model变更了以后,会通过观察者模式(Observer Pattern)通知View;View通过观察者模式收到Model变更的消息以后,会向Model请求最新的数据,然后重新更新界面。如下图:
看似没有什么特别的地方,但是由几个需要特别关注的关键点:
需要特别注意的是MVC模式的精髓在于第三点:Model的更新是通过观察者模式告知View的,具体表现形式可以是Pub/Sub或者是触发Events。而网上很多对于MVC的描述都没有强调这一点。通过观察者模式的好处就是:不同的MVC三角关系可能会有共同的Model,一个MVC三角中的Controller操作了Model以后,两个MVC三角的View都会接受到通知,然后更新自己。保持了依赖同一块Model的不同View显示数据的实时性和准确性。我们每天都在用的观察者模式,在几十年前就已经被大神们整合到MVC的架构当中。
这里有一个MVC模式的JavaScript Demo,实现了一个小的TodoList应用程序。经典的Smalltalk-80 MVC不需要任何框架支持就可以实现。目前Web前端框架当中只有一个号称是严格遵循Smalltalk-80 MVC模式的:maria.js。
MVC的优缺点
优点:
缺点:
MVC Model 2
在Web服务端开发的时候也会接触到MVC模式,而这种MVC模式不能严格称为MVC模式。经典的MVC模式只是解决客户端图形界面应用程序的问题,而对服务端无效。服务端的MVC模式又自己特定的名字:MVC Model 2,或者叫JSP Model 2,或者直接就是Model 2 。Model 2客户端服务端的交互模式如下:
服务端接收到来自客户端的请求,服务端通过路由规则把这个请求交由给特定的Controller进行处理,Controller执行相应的应用逻辑,对Model进行操作,Model执行业务逻辑以后;然后用数据去渲染特定的模版,返回给客户端。
因为HTTP协议是单工协议并且是无状态的,服务器无法直接给客户端推送数据。除非客户端再次发起请求,否则服务器端的Model的变更就无法告知客户端。所以可以看到经典的Smalltalk-80 MVC中Model通过观察者模式告知View更新这一环被无情地打破,不能称为严格的MVC。
Model 2模式最早在1998年应用在JSP应用程序当中,JSP Model 1应用管理的混乱诱发了JSP参考了客户端MVC模式,催生了Model 2。
后来这种模式几乎被应用在所有语言的Web开发框架当中。PHP的ThinkPHP,Python的Dijango、Flask,NodeJS的Express,Ruby的RoR,基本都采纳了这种模式。平常所讲的MVC基本是这种服务端的MVC。
MVP
MVP模式有两种:
而大多数情况下讨论的都是Passive View模式。本文会对PV模式进行较为详细的介绍,而SC模式则简单提及。
历史背景
MVP模式是MVC模式的改良。在上个世纪90年代,IBM旗下的子公司Taligent在用C/C++开发一个叫CommonPoint的图形界面应用系统的时候提出来的。
MVP(Passive View)的依赖关系
MVP模式把MVC模式中的Controller换成了Presenter。MVP层次之间的依赖关系如下:
MVP打破了View原来对于Model的依赖,其余的依赖关系和MVC模式一致。
MVP(Passive View)的调用关系
既然View对Model的依赖被打破了,那View如何同步Model的变更?看看MVP的调用关系:
和MVC模式一样,用户对View的操作都会从View交移给Presenter。Presenter会执行相应的应用程序逻辑,并且对Model进行相应的操作;而这时候Model执行完业务逻辑以后,也是通过观察者模式把自己变更的消息传递出去,但是是传给Presenter而不是View。Presenter获取到Model变更的消息以后,通过View提供的接口更新界面。
关键点:
对比在MVC中,Controller是不能操作View的,View也没有提供相应的接口;而在MVP当中,Presenter可以操作View,View需要提供一组对界面操作的接口给Presenter进行调用;Model仍然通过事件广播自己的变更,但由Presenter监听而不是View。
MVP模式,这里也提供一个用JavaScript编写的例子。
MVP(Passive View)的优缺点
优点:
缺点:
MVP(Supervising Controller)
上面讲的是MVP的Passive View模式,该模式下View非常Passive,它几乎什么都不知道,Presenter让它干什么它就干什么。而Supervising Controller模式中,Presenter会把一部分简单的同步逻辑交给View自己去做,Presenter只负责比较复杂的、高层次的UI操作,所以可以把它看成一个Supervising Controller。
Supervising Controller模式下的依赖和调用关系:
因为Supervising Controller用得比较少,对它的讨论就到这里为止。
MVVM
MVVM可以看作是一种特殊的MVP(Passive View)模式,或者说是对MVP模式的一种改良。
历史背景
MVVM模式最早是微软公司提出,并且了大量使用在.NET的WPF和Sliverlight中。2005年微软工程师John Gossman在自己的博客上首次公布了MVVM模式。
ViewModel
MVVM代表的是Model-View-ViewModel,这里需要解释一下什么是ViewModel。ViewModel的含义就是 "Model of View",视图的模型。它的含义包含了领域模型(Domain Model)和视图的状态(State)。 在图形界面应用程序当中,界面所提供的信息可能不仅仅包含应用程序的领域模型。还可能包含一些领域模型不包含的视图状态,例如电子表格程序上需要显示当前排序的状态是顺序的还是逆序的,而这是Domain Model所不包含的,但也是需要显示的信息。
可以简单把ViewModel理解为页面上所显示内容的数据抽象,和Domain Model不一样,ViewModel更适合用来描述View。
MVVM的依赖
MVVM的依赖关系和MVP依赖,只不过是把P换成了VM。
MVVM的调用关系
MVVM的调用关系和MVP一样。但是,在ViewModel当中会有一个叫Binder,或者是Data-binding engine的东西。以前全部由Presenter负责的View和Model之间数据同步操作交由给Binder处理。你只需要在View的模版语法当中,指令式地声明View上的显示的内容是和Model的哪一块数据绑定的。当ViewModel对进行Model更新的时候,Binder会自动把数据更新到View上去,当用户对View进行操作(例如表单输入),Binder也会自动把数据更新到Model上去。这种方式称为:Two-way data-binding,双向数据绑定。可以简单而不恰当地理解为一个模版引擎,但是会根据数据变更实时渲染。
也就是说,MVVM把View和Model的同步逻辑自动化了。以前Presenter负责的View和Model同步不再手动地进行操作,而是交由框架所提供的Binder进行负责。只需要告诉Binder,View显示的数据对应的是Model哪一部分即可。
这里有一个JavaScript MVVM的例子,因为MVVM需要Binder引擎。所以例子中使用了一个MVVM的库:Vue.js。
MVVM的优缺点
优点:
缺点:
结语
可以看到,从MVC->MVP->MVVM,就像一个打怪升级的过程。后者解决了前者遗留的问题,把前者的缺点优化成了优点。同样的Demo功能,代码从最开始的一堆文件,优化成了最后只需要20几行代码就完成。MV*模式之间的区分还是蛮清晰的,希望可以给对这些模式理解比较模糊的同学带来一些参考和思路。
References
小广告:欢迎follow关注个人github:https://github.com/livoras
The text was updated successfully, but these errors were encountered: