近来看了大师Martin Flower的一些关于UI 架构的文章,为了加强理解特总结如下。
大师从设计的角度入手,阐述了UI 架构的具有代表性跟影响力的模式。其中当然提到了MVC此耳熟能详的模式。并从MVC的源起和演化为我们澄清了对MVC的理解。除了MVC, 大师对UI 架构的其他模式也进行了总结归纳。下面此文简要总结大师对各模式的评述。
1. Forms and Controls
此模式出现于client-server应用盛行之时,晚于MVC的出现。同学们接触过VB, VC, Delphi 跟 PowerBuilder, 应对此不陌生。
Control 就是我们说的 控件(注意不要混淆controller)。 控件是可重用,但跟具体业务逻辑和具体数据不相关的单元。
Form 是特定应用逻辑相关的,跟很多控件相关联,能完成某独立功能的单元。
我们要注意区分Form 跟 自定义控件。 因为自定义的控件可以由多个控件组合而成。 但是Form是跟特定业务逻辑相关的。
界定Form, 可以从Form的两个职责入手。
Form 的 第一个职责就是, Form要负责布局的管理。
第二个职责就是 Form 负责业务逻辑的处理,虽然控件可以承担一些逻辑,但一定存在一些逻辑行为是不能被控件所实现的,有可能是重用的考虑。Form为了完成业务逻辑还需协调各个控件的行为。
在数据层面上,此模式视数据为三层存在。 最终被共享的数据存于数据库中,论文定义为 record state。 论文定义session state 为record state的内存拷贝,之所以冠以session是应为此拷贝是基于应用程序跟数据库的特定的session。最后就是用户看到的screen state。
成熟的Forms and Controls 模式的实现 一般给予 Data Binding, Event framework, Observer 模式来同步数据的三种状态。 数据同步由Form协调进行。
此模式的关键点:
- 编写应用逻辑相关的Form, Form由控件组合而成;
- Form负责其上的控件的布局;
- Form侦听其上的控件所触发的事件,并且对事件做出相应的反应;
- 简单的数据改动通过绑定机制进行同步;
- 复杂的逻辑在Form的侦听方法里进行处理。
2. MVC
MVC概念最早起源于smalltalk。 是最为同学们念叨的一个模式。但最早的经典的MVC概念已经与现在的富客户端有代沟了。所以也导致对这个概念的一些不同的理解跟误用。
寻根追脉,从smalltalk的MVC说起。
这里最关键的是Separated Presentation。而 Separated Presentation的关键就是划分(Domain Object)领域对象跟展示对象(Presentation Objects,不要与下面提到的Presentation Model混淆啊)。Domain Object 是对真实世界,业务领域的模型。Presentation Object是GUI所体现的数据元素。根据Separated Presentation的定义,领域对象要完全独立于展示(Presentation),在独立的前提下可以支持同一数据同时对应多个展示。
注意:我们看到对数据的定义有着完全不同于Form and Control的叫法。Form and Control里是Record State, Session State跟Screen State。 之所以有差异,是我们看数据的角度不同。Form and Control模式对数据的定义基于一个假设,假设就是开发人员是大量基于数据库记录进行开发。MVC假设操作对象是Object。
上面通过核心概念Separated Presentation的描述,我们已经分析出了Model这个概念。剩下View和Controller这两个概念,接着看。
Controller的职责是根据用户的动作规划出怎样处理应对。在View/Controller上需要强调的是,一个应用包含有很多的View-Controller对。在smalltalk的MVC的概念中View-Controller对构成一个组件(component)。View跟Controller一同组成展示部分。
Smalltalk的MVC上,数据更新通过Controller更新到Model。另一方面View通过Observer得到Model的更新。注意这里跟Form and Control有很大不同。Flow and Control以Flow Synchronization( 屏幕代码直接,直观地更新model,直接通知共用此模型的其他控件。但这样也导致了屏幕代码之间的耦合。适合一些简单的界面,例如,root-child风格的模态框,我们关闭模态框直接通知到他的root窗口,这样很直接。)的方式进行数据同步。MVC以Observer Synchronization(适合统一分数据同时对应多个屏幕,但代码相对更难理解)进行同步。
讨论完了数据同步问题,接下来对于MVC还有一个些尴尬的问题。阐述这个问题,我们从例子引入,如果我们的model有两个值,根据两个值的差值的范围来设置某一控件的颜色。计算差值,进一步把差值映射到具有领域意义的属性,这部分职能由model负责,并不难理解。但是从model的属性再映射到颜色的显示这相关逻辑应该放在何处? 在早期的smalltalk里,这个问题的解决方式就是打破领域模型的纯洁性,把这部分逻辑参合进领域模型中。这是一种不优雅的做法,但我们可以偶尔为之 :)。另一种相对好的做法就是,我们封装自己的控件,控件中包含一张值与颜色的对照表,这部分映射逻辑就封装进自定义控件。这种做法的前提是我们要可以很方便地subclass要封装的控件。最后还有一种做法是我们可以添加一种新的model对象。这种对象面向显示,其中要用到领域对象的部分通过代理(delegate)实现。我们称这模型为展示模型(Presentation Model)。
我们再来汇总一下MVC重要之处:
- Sparated Presenation, 展示(View 跟 Controller)要严格区分 模型(model).
- 把GUI Widget分成View跟Controller,他们共同组成widget。 Controller负责(单独,直接)反应用户的请求,点击。View负责显示状态。View跟Controller通过Model进行交互。
- 通过Observer Synchronization, 让View对Model进行同步。同时支持一份数据对应多个View。
3. MVP (Model-View-Presenter)
这个模式最早出现于IBM。常见于上世纪90年代一面向对象操作系统Taligent。
MVP试图融合前两种模式的优势。Form and Control的简单直观。MVC的支持同意数据上的多View。
下面我们通过比较来阐明MVP。
跟Form and Control对比,MVP的View更像Control。View直接接收用户的刺激再转手给Presenter。
跟MVC比。MVP的展示部分不分为View/Controller两部分,MVP的View就是展示部分。Presenter可为Supervising Controller,但不同于MVC的Controller, Presenter不直接反应用户刺激。用户刺激都是·经View转手到Presenter。在不好适用Observer Synchronization的时候,Presenter可以直接操作显示组件。
MVP的Presenter跟MVC的Controller存在很大的相似性。Presenter是一种松散形式的MVC Controller。所以在很多框架实现中,实现的虽然是MVP风格,但Presenter被叫作Controller。
要点总结:
- View部分widget直接接受用户刺激,再转手给Presenter.
- Presenter再负责协调model的改变。
- 在处理View的更新问题上,此模式相当宽松。各种实现都可以,从使用Observer Synchronization到直接由presenter更新。
4.Humble View
Humble View的出发点是测试。尤其敏捷开发,我们流行写自测试的代码(Self-testing)。而UI的测试在这方面一直比较尴尬,原因是UI代码直接跟展示基础平台耦合。这种情况下,很多研究极力最小化那些难以测试的对象行为,这就是Humble Object。
前面几节中我们提到的Presentation Model跟Supervising Controller都朝这个方向做出了相应的贡献。我们可以测试Presentation Model跟Supervising Controller,剩下humble object里的逻辑就难以覆盖到了。在Presentation Model情况下,所有的逻辑决策都由Presentation Model负责。所有用户事件跟显示逻辑都被路由到Presentation Model。Widget只负责映射到Presentation Model的属性。这部分映射很难Self-testing。在Supervising Controller中这种不能Self-testing的映射可以控制在更小的范围内,原因是Supervising Controller将不需要映射来操作widget来应付一些复杂的情形。
还有一个为测试而生的模式,这里要提到的就是Passive View(MVC跟MVP的变种)。它在Humble Object上做出了最大努力。Passive View不仅用Controller来反应用户事件,还用它来更新View(跟MVC相比,这里View不再依赖Model)。这样UI组件的逻辑行为被减少到了最少(相对Presentation Model跟SuperVising Controller,因为这两个还需要View来负责更新)。
本文出自 “洪流的博客” 博客,请务必保留此出处http://simonwzing.blog.51cto.com/3896700/1632202
原文地址:http://simonwzing.blog.51cto.com/3896700/1632202