• AV(Autonomous View)自治视图

    • 在面向终端用户的应用中,都需要一个可视化的UI来与用户交互.这个UI称为View视图.
    • 在早期,我们习惯将所有前台的逻辑,与视图揉在一起,称为AV自治视图.
      • 这些逻辑包括:数据呈现(Display),用户动作的扑捉与响应,数据存储等.
    • 在.Net的Winform和ASP.NET Web Form中,采用的都是事件驱动模型.
    • AV是将所有UI相关的逻辑都注册到视图本身,或者视图元素对应的事件上.
    • 人机交互应用的3个关注点.
      • 数据在UI上的展示.
      • UI处理逻辑.
      • 业务逻辑.
    • AV的缺陷
      • 首先,业务逻辑与UI无关,所以应该最大程度地被重用.而在AV中,业务逻辑糅合在UI中,无法重用.例如,从winform迁移到web form上.
      • 稳定性:业务逻辑>UI处理逻辑>UI.
        • 而3者糅合在一起后,具有最弱稳定性的UI决定了整体的稳定性.
        • 这属于典型的"短板效应".
      • 任何涉及到UI的组件都是不可测试性的(至少是很难测试).所以AV对测试不友好.
  • MVC模式
    • 针对AV的缺陷,采用SOC(关注点分离)来剥离3个部分.
    • 将人机交互应用分为3个部分
      • Model:对应用状态和业务功能的封装.

        • 维护着整个应用的状态(数据和行为),并实现了所有的业务逻辑,可以看做为一个领域模型.
      • View:实现可视化界面的呈现,捕捉最终用户的交互操作(键盘,鼠标).
      • Controller.
        • View捕获到用户交互操作后会直接转发给Controller,后者完成相应的UI逻辑。
        • 如果需要涉及业务功能的调用,Controller会直接调用Model。
        • 在完成UI处理之后,Controller会根据需要控制原View或者创建新的View对用户交互操作予以响应.
    • View和Model存在直接的联系.
      • View可以直接调用Model查询其状态信息。
      • 当Model状态发生改变的时候,它也可以直接通知View.
    • Model对View的数据状态改变通知,View对Controller的用户交互通知.都是单向的消息交换.
      • 可以使用事件机制来实现这两种通知.
      • 也可以通过观察者模式通过注册/订阅的方式来实现.
        • View作为Model的观察者,通过注册相应的事件来检测数据状态的改变.
        • Controller作为View的观察者,通过注册相应的事件来处理用户的交互操作.
  • MVP模式
    • MVC模式存在的问题

      • View和Model可以绕过Controller来直接进行交互.
      • 对于用户驱动的程序(人机交互),我们不需要Model来主动通知View数据状态的变化.所以,Model应该是完全独立的.
    • MVP模式的目标
      • 测试(Unit Test)友好.
      • 关注点分离.
      • 正交性.
        • 每一个操作都只改变一件事情,而没有其它的副作用.
    • 解依赖
      • 对View和Model解耦.
      • 降低了Presenter对View的依赖.从依赖于具体的View到依赖于抽象的IView接口.
    • 交互
      • Presenter对Model的单向调用.
      • Presenter和View之间的双向交互.这个是核心.
    • Presenter和View之间交互的方式
      • PV(Passive View)

        • 为了不做对UI的测试(难到几乎不能),应该在UI中不进行UI逻辑的处理.
        • 一个被动的View.View中的UI元素(控件)不是由View本身操作,而是由Presenter控制对UI元素的操作.
        • 需要将View中的元素以属性或者其他方式暴露,以供Presenter操作.
        • 在数据绑定中,控件类型的选择应该是View内部的逻辑,不应该出现在Presenter中.
          • 所以,在IView的定义中,不能涉及到具体的控件类型.
          • 而是返回一种数据绑定所需的数据类型.
          • 然后在View内部处理数据到控件的绑定.
        • PV对测试友好,因为所有的UI处理逻辑都在Presenter中,便于测试.
        • 缺陷
          • 对于一个复杂的UI(含有很多元素),IView接口将会十分庞大.
          • Presenter需要对UI元素进行操作,所以要了解很多的UI细节.造成简单事情复杂化.
      • Soc
        • 将诸如格式化,数据绑定这些简单的UI逻辑移到View中.在View中进行一些简单的UI逻辑处理.
        • View本身仅实现单纯独立的UI逻辑,它处理的数据应该是Presenter推送给它的.
          • 所以View尽可能不维护数据状态.在Iview接口的定义中不包含属性.
        • Presenter所需的View状态应该是View在请求交互处理时给它的.
  • 第一次改造:最薄的View.
    • 起源:由于View持有对Presenter的引用,所以理论上,View是可以无限制地调用Presenter的.

      • 基于以前AV的编码习惯,很可能造成以下的问题:

        • 大部分(甚至所有)的UI处理逻辑都写到View中.
        • 而Presenter的作用就是Proxy,仅仅是调用View中的方法而已.
    • 采用事件订阅的方式来完成Presenter和View的交互.
      • 首先,在IView中定义事件Handler.
      • 为了隔离事件参数中e的类型污染(一些控件的事件参数,会引入一些测试不友好的类型),定义一系列的事件参数类型.
      • 然后,在View的控件事件处理函数中.
        • 将处理事件需要的上下文信息,包装到一个自定义的事件参数中,然后 Raise Event.
      • 最后,在Presenter中,订阅IView暴露的各种事件,并进行处理.处理时需要的上下文在自定义的事件参数中.
    • 优缺点
      • View只完成了纯粹的布局展示.
      • 在事件处理流程中,如果需要Cancel处理,会比较难做到.
  • 第二次的改造
    • 在View中调用Presenter的方法.完成部分的UI逻辑.
    • 工程划分(使用Company来替代真实信息).
      • Company.MVP.ICommonView.

        • 包含了对使用到的控件的抽象View接口,在每个接口中暴露出来Presenter需要使用到的属性和函数.
        • 每一种控件类型一个接口.
      • Company.MVP.ComonViews.
        • 对于每一个控件,实现一个继承了IXXXView接口的类.
        • 在这些类中,体现了具体控件的属性和方法的细节.
      • Company.MVP.Common.
        • 该工程含有3个子文件夹.
          • ModelObjects. Model的一部分,业务模型的抽象类.
          • Service. Model的另外一部分,定义了数据访问接口.
          • View:定义了UI页面需要实现的接口.
      • Company.MVP.Presenter.
        • Presenter的具体实现.
      • Company.MVP.Service.
        • 数据访问接口的具体实现.
      • Company.Client.
        • 具体的UI工程.会实现Common中View的UI页面接口.
    • 工程间依赖.
      • Prensenter仅仅依赖于ICommonView和Common.而跟具体的UI控件类型,具体的UI画面无关.
      • 所以,可以使用一个Presenter来对应多个的View展示(Client).
    • 单元测试
      • 针对Presenter.

        • 对于Service和View,由于P中操作的是两者的接口.所以可以使用Mock来模拟这两个部分.
        • 而Model是可以简单地New出来的,不需要进行Mock.
      • 针对Model.
        • 使用业务场景,进行测试.而且对其测试时,不需要进行Mock.
      • 针对View.
        • 可以进行少量的测试.因为有IView接口,所以可以Mock控件的属性和行为,来针对UI页面进行测试.
    • 更换控件类型
      • UI应用中,最经常遇到的情形.例如,现在要将界面上的一个TextBox控件替换为EditText控件.

        • 在UI实现的Client工程的具体页面类上,将实例化以前的成员时使用的类型从TextBoxView修改为EditTextView即可.
        • 其他的类和工程不需要修改.
        • 改动被限定在了特定的地方.避免了短板效应.
  • 总结
    • 关于代码量

      • 使用MVP模式后,代码量是肯定不会比原先的少的.
      • 考虑到View的重用,以及子Presenter的重用.代码量增加的也不多.
    • 关于控件的View类型的接口抽象及实现.
      • 对于控件的View的接口,可以只针对一个页面,也可以在工程前期,定义好对一个控件所需的所有的操作.这样就在全系统中使用一份View的接口.
      • View接口对外暴露的应该是操作,而不是以控件属性/方法的视角看待.也就是说Prensenter需要对控件进行什么类型的操作,就暴露一个这样的操作出来.
    • 关于控件差异性的问题.
      • 系统中不同界面中,同一控件的操作接口可能是不同的.
      • 按照MVP的本意,是没有View重用的概念的.
      • 但是,我们可以将同一控件基本的公用行为抽象为一个接口,然后使用一个类来实现它.然后在有特殊操作接口的画面中,再定义一个继承自公用接口的接口,然后使用一个类继承公用类,并实现该接口.
    • 关于控件的事件链.
      • 在现有的代码中,有很多地方用到了事件链的连锁效应.
      • 个人认为,这是一种不太好的编程方式.这样控件之间相互的依赖关系变得如此的复杂.改动事件链上的任何一个控件的任何一个事件处理,都需要查看其连带的连锁反映.
      • 在MVP中,我们在处理一个控件的操作时,会把所有控件需要展示的内容一次性地处理好,然后一把交给View进行展示.而不是使用事件的连锁效应.
      • 这样,就解除了控件之间在事件上的相互依赖关系.
    • 关于单元测试.
      • 对于业务系统的单元测试,纯粹的代码覆盖率是没有意义的.
      • 需要关注的是测试的场景覆盖率.
      • 即使覆盖百分百的代码.但是漏测了一种Case,一样会出现Bug.
      • 所以,我们需要有很清晰的业务逻辑说明,来指导我们进行单元测试时的Case场景输入.
    • 事件处理流程三部曲
      • IView中定义Event.
        • Event ButtonClick.
      • View中触发事件.
        • Private withevents  _item as button
            Public sub itemClick() handles _item.Click
          RaiseEvent  ButtonClick
      • Presenter中挂接并处理事件
        • AddHandler OKButton.ButtonClick , Addressof  Save.
    • 目标
      • 一个(种)控件,对外提供统一的行为接口.
        • 行为包括:属性,方法,事件.
      • 画面类职责清晰.
        • 仅包含了控件的集合.
        • 没有任何的逻辑处理代码.
      • 更换控件类型时,改动最小.
        • 仅需更改画面类中New控时使用的实际View类型.
      • 业务代码和控件逻辑的分离.
        • 业务代码放在Model中.
        • 控件逻辑,封装在View的实际实现类中.
        • Model是完全独立的,不依赖于任何模块.

应用MVP模式对遗留代码进行重构的更多相关文章

  1. Android MVP模式 谷歌官方代码解读

    Google官方MVP Sample代码解读 关于Android程序的构架, 当前(2016.10)最流行的模式即为MVP模式, Google官方提供了Sample代码来展示这种模式的用法. Repo ...

  2. android MVP模式介绍与实战

    android MVP模式介绍与实战 描述 MVP模式是什么?MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数 ...

  3. 从最简单的HelloWorld理解MVP模式

    版权声明:本文为博主原创文章,转载请注明出处:http://www.cnblogs.com/joy99/p/6116855.html 大多数编程语言相关的学习书籍,都会以hello,world这个典型 ...

  4. 使用MVP模式重构代码

    之前写了两篇关于MVP模式的文章,主要讲得都是一些概念,这里谈谈自己在Android项目中使用MVP模式的真实感受,并以实例的形式一起尝试来使用MVP模式去重构我们现有的代码. 有兴趣的童鞋可以先去阅 ...

  5. MVP模式, 开源库mosby的使用及代码分析

    Android中的构架模式一直是一个很hot的topic, 近年来Architecture components推出之后, MVVM异军突起, 风头正在逐渐盖过之前的MVP. 其实我觉得MVP还是有好 ...

  6. Android MVP模式

    转自http://segmentfault.com/blogs,转载请注明出处Android MVP Pattern Android MVP模式\[1\]也不是什么新鲜的东西了,我在自己的项目里也普遍 ...

  7. .Net平台-MVP模式初探(一)

    为什么要写这篇文章 笔者当前正在负责研究所中一个项目,这个项目基于.NET平台,初步拟采用C/S部署体系,所以选择了Windows Forms作为其UI.经过几此迭代,我们发现了一个问题:虽然业务逻辑 ...

  8. Android开发之初识MVP模式

    各位亲爱的小伙伴,有没有想我啊,我胡汉wing又回来了. 很长一段时间没有更新博客..原因是..从离职回到学校以后,一直在享受最后的学生时光(打游戏).. 游戏固然很爽,但是觉得实在很荒废,于是半夜诈 ...

  9. MVP 模式简单易懂的介绍方式

    为什么用Android MVP 设计模式? 当项目越来越庞大.复杂,参与的研发人员越来越多的时候,MVP 模式 的优势就充分显示出来了. MVP 模式是 MVC 模式在 Android 上的一种变体, ...

随机推荐

  1. Arduino LM35温度检测

    一. 接线原理图 二.实物图 三.代码例子

  2. AndroidStudio 内存泄漏的分析过程

    前言部分这次泄漏是自己代码写的太随意引起的,讲道理,代码写的太为所欲为了,导致有些问题根本就很难发现. 泄漏产生的原因,由于activity未被回收导致.这里给我们提出的一个警示,在使用上下文的时候, ...

  3. HTML 1.1页面js修改文字颜色

    昨天的报告页面,想要实现根据不同文字内容改变字体颜色,效果图: 调试了半天出不来效果,最后请教了前端,上代码: <!DOCTYPE html> <html lang="en ...

  4. 启动模拟器的qq

    #coding = utf-8from appium import webdriver '''1.手机类型2.版本3.手机的唯一标识 deviceName4.app 包名appPackage5.app ...

  5. AtCoder Grand Contest 021完整题解

    提示:如果公式挂了请多刷新几次,MathJex的公式渲染速度并不是那么理想. 总的来说,还是自己太弱了啊.只做了T1,还WA了两发.今天还有一场CodeForces,晚上0点qwq... 题解还是要好 ...

  6. Modbus串行通信

    一.Modbus通信协议简介 1. Modbus协议 Modbus 是一个请求/应答协议,并且提供功能码规定的服务.Modbu协议是 OSI 模型第 7 层上的应用层报文传输协议. MODBUS协议支 ...

  7. Oralce导入数据库出现某一列的值太大

    这是由于导出的文件所运行的Oracle,和导入所运行的Oracle机器字符集不相同导致的,在UTF-8中有的汉字占三个字节, 并不是所有的都占两个字节,

  8. Linux思维导图之文件压缩

  9. 单例模式的理解【php】

    单例模式(Singleton Pattern):顾名思义,就是只有一个实例.作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 为什么要使用单例模式 1.P ...

  10. jupyter记事本的安装和简单应用

    1.概述 jupyter记事本是一个基于Web的前端,被分成单个的代码块或单元.根据需要,单元可以单独运行,也可以一次全部运行.这使得我们可以运行某个场景,看到输出结果,然后回到代码,根据输出结果对代 ...