MVC 已经成为客户端的主流编程框架,相信客户端工程师对它并不陌生,甚至在开发过程中,不通过思考都会自动使用 MVC 框架编程。但在工作过程中,发现许多小伙伴也只是使用 MVC,对于为什么这样使用并不清楚。本篇文章将由浅入深,一步一步解释为什么要使用 MVC,以及使用 MVC 所带来的好处。

刚开始工作时,我是这样快速完成任务的

在刚开始工作时,拿到一个任务,第一时间想到的是怎么将它快速实现,但从未想过怎么将它做好,代码从头到尾都在文件里,一气呵成,速度比别人要快一倍,然后坐在那里,静静的等待着下一个任务的到来,有时还会偷偷的鄙视一下比我做得慢的同事,心中窃喜。但随着项目慢慢变大,问题就来了,一个 Controller 里的代码有时候会变成上千行,甚至几千行,代码的可读性变得非常差,存在大量重复代码,项目的一个小变更经常无法定位代码。经常干的事情就是全局搜索,替换相同的代码,一不小心改错一个,半天的工作得从头开始。

当年代码是这样的(伪代码):

这是一段简短的代码示例,但确能看出很多的问题。API 未封装、无统一网络接口、数据没模型、无任何编程思想等。

头破血流后,意识到代码复用的重要性

项目渐渐变大,编码几乎无法继续下去,面对需求变更,除了头疼,还是头疼。都说人感到痛苦的时候就是在成长,说得没错,这是我的第一次成长。在完成工作任务的空闲时间里,我开始试着重构自己的代码。我知道我所面对的直接问题是重复代码太多,需要代码复用,但对于工作经验不足的我,首先想到复用方法是函数。把网络请求、数据解析、数据存储、逻辑处理、页面刷新等都封装成了函数,代码结构瞬间变得清晰起来,Controller 里面代码减少 20%,成就感满满的。

项目越来越复杂,功能也一直在增加。渐渐发现自己的开发速度又在慢下来,上司对我工作也开始表现出不满。我知道自己的这种复用机制已经不能应对项目的复杂度。虽然在一个 Controller 里代码是可以复用了,但不同 Controller 之间的复用都是通过拷贝的,重复代码还是很多。而且拷贝过去后还要读懂其他逻辑,代码耦合度非常高。更糟糕的是,一个网络请求如果要增加或者减少一个 Header 参数,又得全局搜索,将所有文件都更改一遍,可扩展性极差。

改进后的伪代码:

虽然改进后代码还是很糟糕,但是代码可读性有了提高,并且同样接口调用已经不需要写第二次。

原来还有代码职责这回事

无论你考虑问题多么认真,限于已有知识的限制,做的事情不可能百分百完美,问题还是会接踵而来。当项目越来越大,工程文件目录越来越复杂,编写代码时变得非常困惑,不知道代码到底应该写在哪里,也不知道别人是不是已经曾经实现过类似的功能,到哪里去引用。或者有时候改一个页面属性,到处改都不生效。后来才发现在某个角落里,你已经对这个属性进行了修改。

这就是代码职责不清晰所造成的。比如在 View 里面只负责页面创建和刷新、Model 里面只负责数据处理和逻辑处理、Controller 只负责接口调用,连接 View 和 Model,并管理它们的生命周期。如果在 Controller 里面写了创建页面的代码,那么就是破坏了类的单一职责。一个类,只有一个引起它变化的原因。应该只有一个职责。每一个职责都是变化的一个轴线,如果一个类有一个以上的职责,这些职责就耦合在了一起。这会导致脆弱的设计。当一个职责发生变化时,可能会影响其它的职责。另外,多个职责耦合在一起,会影响复用性

职责不清晰就会造成代码耦合度高,破坏代码的复用性,并且代码的维护成本也变高。每一个类有每一个类的职责,每一类类有每一类类的职责,在项目开发前就都规定好,在后面的多人合作开发中就有规可循,编写对应功能的代码知道写在对应目录上,类似功能代码可以去固定文件夹中寻找,更改页面属性是只需考虑页面内代码。做到轻松愉快编程。

最后,终于明白了封装和继承的好处

庆幸的是,我的烂代码在项目演进而蔓延中,但并没有酿成不可挽回之势。我及时意识到了问题的严重性。

随着工作经验的积累,学到的技术越来越多,封装和继承在这正好能解决代码重用度低和可扩展性差的问题。于是我开始第二次重构自己代码。我写了个网络请求的基类,所有网络请求在这里都有个唯一出口,相同类型的网络请求我将他封装在一个类中,并且每个网络请求都有接口。数据我给它建立对应的模型,并在模型中解析对应数据源,再建立一个类来负责这个模型数据的增删改查和更新,如果有数据缓存,再创建一个类来管理这个模型的数据存储。这样一来,在不同 Controller 中用到同样的数据请求或模型,只需引用对应的类,调用相应的接口就行,不在需要再去理解相关代码逻辑,或者看 API 文档,真正实现了代码的封装性和复用性。而且网络接口类,模型类都有对应基类,代码的可变更性和扩展性也得到了保障。

改进后伪代码:

摸爬滚打中和 MVC 第一次相识

第一次相识,并不是指第一次听说,MVC 一直贯穿编程过程中,只是第一次感觉对它有些理解。做完代码职责后,就已经大体上遵循了 MVC 编程框架思想。只是上面没有特别说明将视图剥离出来。

MVC 全名是 Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一个框架模式。MVC 三部分组成,各司其职,结构清晰明朗。程序的业务逻辑、数据、界面显示完全分离,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。

Model(模型)表示应用程序数据,逻辑处理,数据库记录列表。模型能为多个视图提供数据,由于应用于模型的代码只需写一次就可以被多个视图重用,所以减少了代码的重复性。

View(视图)是应用程序中处理数据显示的部分,视图处于交互层,用于将数据展示给用户,并传达用户的操作指令。

Controller(控制器)是应用程序处理用户交互的部分,通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。

如下图所示:MVC 中 M 与 V 两者不存在任何直接交互。存在直接交互的只有 M 和 C 之间与 C  和 V 之间。首先我们来看 M 与 C 的交互,如图所示,有一条绿色的箭头从 C 发起指向了 M,代表了 C 与 M 之间的交互应该首先从 Controller 发起,C 首先向 M 提出自己的需求,再由 M 作出响应。C 具有导入 M 头文件的 API,因此 C 可以知晓 M 的一切内容,如同图中的那一条白色的虚线。再来看看相对复杂的 C 与 V 之间的交互,这次我们仍然从绿色的箭头开始了解,箭头仍然由 C 发起,可见 C与 V 之间的交互依旧由 Controller 发起,但箭头起始端写了 outlet 一个词,意思是“输出口”,outlet可以看作是从 C 指向 V 的指针,它在 C 中被定义。outlet 给我们提供了很大的方便,它使我们在 C 的内部就可以轻松准确地向 V 施令。C 可以拥有很多的 outlet,可以不止一个,这也使它可以更高效的和V进行交流。

我们以一个页面展示网络数据为例,来说明 MVC 之间元素的通信。首先用户通过 View 发出指令要刷新页面数据,然后 View 把这个指令通过 outlet 或 delegate 传达给 Controller,Controller 向 Model 提出要给它数据,Model 完成数据组织后返回给 Controller,Controller 再通过 data source 刷新 View。到这里,一条完整的通信就完成了。

为什么要用 MVC

MVC 的低耦合性、高重用性、可维护性等优点显而易见,使得原本复杂的代码与界面的交互变得简单、清晰、明了。而且 MVC 不同的层各司其职,有利于多人协作开发项目。

在我经历的几个工作阶段中,第一阶段编码无任何编程思想,所有代码都混杂在一起,显得混乱不堪,可读性非常差。要找一段逻辑,经常无法定位。

第二阶段知道用函数来包装一些重复代码,使得代码结构变得清晰。如果说之前编程思想是一页白纸的话,那么这一过程我开始在这页白纸上画了一笔,收获了面向过程的思想。编程思路渐渐清晰起来。

第三阶段开始接触继承和封装这些面向对象的高级特性,真正解决了之前编程过程中所面对的代码可读性差、复用性低、可维护性难等问题。如果把编程思想比作画画,那么经过这一阶段我已经能在白纸上画出形状。

第四阶段主要学会了和人协作。

而 MVC 的出现就是为了解决我们在工作各阶段所面临的问题,学习 MVC 编程框架,可以让你不用经历我所走过的弯路。

由浅入深吃透MVC框架,驯服烂代码的更多相关文章

  1. IceMx.Mvc 我的js MVC 框架 一、html代码的分离(视图)

    介绍 本人菜鸟,一些自己的浅薄见解,望各位大神指正. 本框架有以下优点 1.简单(调用简单.实现简单.不过度设计) 2.视图.控制器.模型分离(分离对于维护十分有必要) 3.组件化(每一个mvc模块儿 ...

  2. 手写MVC框架(二)-代码实现和使用示例

    --------上一篇:手写MVC框架(一)-再出发----- 背景 书接上文,之前整理了实现MVC框架需要写哪些东西.这周粗看了一下,感觉也没多少工作量,所以就计划一天时间来完成.周末的时间,哪会那 ...

  3. MVC系列——MVC源码学习:打造自己的MVC框架(四:了解神奇的视图引擎)

    前言:通过之前的三篇介绍,我们基本上完成了从请求发出到路由匹配.再到控制器的激活,再到Action的执行这些个过程.今天还是趁热打铁,将我们的View也来完善下,也让整个系列相对完整,博主不希望烂尾. ...

  4. 自己动手写PHP MVC框架

    自己动手写PHP MVC框架 来自:yuansir-web.com / yuansir@live.cn 代码下载: https://github.com/yuansir/tiny-php-framew ...

  5. 自己写一个java的mvc框架吧(一)

    自己写一个mvc框架吧(一) 目录 自己写一个mvc框架吧(一) 自己写一个mvc框架吧(二) 自己写一个mvc框架吧(三) 自己写一个mvc框架吧(四) 写之前的一些废话 废话 1 (总是要先随便说 ...

  6. 开源:Taurus.MVC 框架

    为什么要创造Taurus.MVC: 记得被上一家公司忽悠去负责公司电商平台的时候,情况是这样的: 项目原版是外包给第三方的,使用:WebForm+NHibernate,代码不堪入目,Bug无限,经常点 ...

  7. 基于AOP的MVC拦截异常让代码更优美

    与asp.net 打交道很多年,如今天微软的优秀框架越来越多,其中微软在基于mvc的思想架构,也推出了自己的一套asp.net mvc 框架,如果你亲身体验过它,会情不自禁的说‘漂亮’.回过头来,‘漂 ...

  8. 编写自己的PHP MVC框架笔记

    1.MVC MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器(Controller). ...

  9. 制作自己的MVC框架(一)——简单粗暴的实现

    现在市面上有很多成熟的MVC框架,可以拿来直接用,但自己造一下轮子其实也挺有意思的. 下面先来看个最简单粗暴的MVC实现. 5个文件就能实现最简单的MVC,在Apache中设置一个虚拟目录,配置个简单 ...

随机推荐

  1. c# 左连接写法

    var itemandformulas = from i in AttendanceItemList join f in AttendanceFormulaList on i.AttendanceCo ...

  2. Solaris用户管理(一):用户与组管理

    Solaris用户管理(一):用户与组管理  2008-07-01 09:19 用户管理是系统管理的基础.Solaris中不但支持传统Unix所支持的用户和组的概念,还从Solaris 8开始引入了基 ...

  3. angularjs 利用filter进行表单查询及分页查询

    页面: <div> <input style="width:90%;margin-left:5px;margin-right:5px;" class=" ...

  4. app图标和启动页设置

    弄了一下午,终于把iOS中图标的设置和启动页的设置弄明白了.我想以后再也不会浑了. 进入正题: 一:apple 1).iPhone4s 3.5寸屏,也就是640*960,但在模拟器上正常用的是320* ...

  5. [转]单例模式与静态变量在PHP中

    在PHP中,没有普遍意义上的静态变量.与Java.C++不同,PHP中的静态变量的存活周期仅仅是每次PHP的会话周期,所以注定了不会有Java或者C++那种静态变量. 所以,在PHP中,静态变量的存在 ...

  6. Ubuntu 12.04下解决Rhythmbox Music Player乱码问题

    1.打开终端输入如下信息: $ sudo gedit ~/.profile 2.在打开的文档末尾加上如下两句: export GST_ID3_TAG_ENCODING=GBK:UTF-8:GB1803 ...

  7. mysql 语句资料总结

    一.UNION命令 UNION 操作符用于合并两个或多个 SELECT 语句的结果集. 请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列.列也必须拥有相似的数据类型.同时,每条 SE ...

  8. 响应式设计的5个CSS实用技巧

    正如我在教程响应式Web设计三步走当中所讲的,响应式的Web设计其实并不难,但是要让元素在布局切换时能够平滑过渡就比较考验技巧了.现在我分享在编码时常用的五个CSS技巧并举例说明.这些技巧都是使用简单 ...

  9. C#中静态方法和非静态方法的区别(二)

    一.引言 在C#中,静态和非静态的特征对于我们来说是再熟悉不过了,但是很少看到有一篇文章去好好地总结静态和非静态它们之间的不同,为了帮助大家更好地去理解静态和非静态特征, 所以将在这篇文章中帮大家全面 ...

  10. Java初试

    另外在Java语言的代码内部书写文件路径时,需要注意大小写,大小写需要保持一致,路径中的文件夹名称区分大小写.由于’\’是Java语言中的特殊字符,所以在代码内部书写文件路径时,例如代表“c:\tes ...