MVC 无人不知, 可很多程序员对 MVC 的概念的理解似乎有误, 换言之他们一直在错用 MVC, 尽管即使如此软件也能被写出来, 然而软件内部代码的组织方式却是不科学的, 这会影响到软件的可维护性, 可移植性, 代码的可重用性.
MVC 即 Model,View,Controller 即模型, 视图, 控制器. 我在和同行讨论技术, 阅读别人的代码时发现, 很多程序员倾向于将软件的业务逻辑放在 Controller 里, 将数据库访问操作的代码放在 Model 里.
最终软件 (网站) 的代码结构是, View 层是界面, Controller 层是业务逻辑, Model 层是数据库访问.
不知道大家知不知道另外一种软件开发模式三层架构, 它和 MVC 相似之处是也分为三层, 分别是 UI 层表示用户界面, BLL 层表示业务逻辑, DAL 层表示数据访问. 三层架构曾经红极一时, MVC 大行其道之后它就销声匿迹了, 可现在看来, 它似乎只是改头换面, 装扮成 MVC 的样子, 并且深受程序员们的欢迎, 因为它的这种分层方式和前文描述的 MVC 如出一辙.
再说的直白点, 很多程序员将 MVC 当成了三层架构在用, 这看起来似乎没什么问题, 毕竟三层架构也是一种和 MVC 齐名的架构模式. 可问题在于用三成架构的思路写 MVC, 那么写出来的东西既不是三成架构也不是 MVC, 到是像一个什么都不是四不像. 熟悉天龙八部的同学应该知道这样一段情节, 吐蕃番僧鸠摩智强行用道家的小无相功为基础修炼少林的七十二绝技和易筋经最终导致走火入魔. 其实用这个例子来形容现在一些程序员用三层架构的思想写 MVC 最恰当不过了, 三层架构的核心思想是面向接口编程和各层之间的解耦和可替换性, MVC 框架中没有这种概念, 因为 MVC 要面对的问题本就不是三成架构要面对的问题, 所以以 MVC 为基础写出来的三成架构是不会具备三层架构的核心要义的, 换言之, 这种代码是放弃了三层架构和 MVC 的精华, 获得了它们的糟粕, 是愚蠢的编码方式.
我吐槽了这么多, 对于吐槽的理由要是说不出个所以然来, 估计要被人喷死, 下面就来说说 MVC 本质原理和正确使用方式, 当然, 这里的 MVC 指的最纯粹 MVC, 适合各类软件, 而不仅仅指 web 框架中的变体 MVC, 然而万变不离其宗, 文中所述的 MVC 思想同样适用于 Web 开发.
MVC 要实现的目标是将软件用户界面和业务逻辑分离以使代码可扩展性, 可复用性, 可维护性, 灵活性加强.
View 层是界面, Model 层是业务逻辑, Controller 层用来调度 View 层和 Model 层, 将用户界面和业务逻辑合理的组织在一起, 起粘合剂的效果. 所以 Controller 中的内容能少则少, 这样才能提供最大的灵活性.
比方说, 有一个 View 会提交数据给 Model 进行处理以实现具体的行为, View 通常不会直接提交数据给 Model, 它会先把数据提交给 Controller, 然后 Controller 再将数据转发给 Model. 假如此时程序业务逻辑的处理方式有变化, 那么只需要在 Controller 中将原来的 Model 换成新实现的 Model 就可以了, 控制器的作用就是这么简单, 用来将不同的 View 和不同的 Model 组织在一起, 顺便替双方传递消息, 仅此而已.
合理的使用 MVC 有很多好处, 要一一道尽是一件异常困难的任务. 在这里我们通过一个反面示例来侧面的证明正确使用 MVC 的好处与依据.
如前文所言, 很多程序员偏爱于将业务逻辑放在 Controller 中, 我极力反对这种做法, 现在我就来证明这中做法的错误性.
我们知道在写程序时, 业务逻辑的重复使用是经常要面对的场景. 如果业务逻辑写在控制器中, 要重用它的唯一方法就是将它提升到父类之中, 通过继承来达到代码复用的效果. 但这么做会带来一个巨大的副作用, 违背了一项重要的面向对象设计原则: 接口隔离.
什么是接口隔离, 我在这里简单的讲述一下. 通俗一点讲, 接口隔离就是当一个类需要继承另一个类时, 如果被继承的类中有继承的类用不到的方法或者属性时, 就不要去实现这个继承. 如果真的情非得已必须要继承, 那么也需要从被继承的类中再提取出一个只包含需要部分功能的新类型, 最终去继承这个新类型才是正确的做法. 换句话说, 实现继承的时候, 不要去继承那些用不到的事物.
回到之前的话题, 通过继承父控制器的方式复用业务逻辑时, 往往会出现为了重用一个方法而继承来一大堆用不到的方法, 表面上看起来似乎没什么问题, 但是这会使代码变的难以理解,
长此以往, 软件的代码会朝着不健康的方向发展.
要知道, 使用继承的条件是很苛刻的, 我们学习面向对象变编程继承特性时, 第一课就是只有满足 IS-A(是一个)关系时才可以使用继承, 如果仅仅是复用代码, 并不是我们使用继承的理由. 使用组合是复用代码提倡的方式, 也就是所谓的 HAS-A(有一个)的关系, 相信每个程序员都听过 "少用继承, 多有组合" 这句话, 这句话是软件开发业的先驱们千锤百炼总结出来的, 值得我们去遵循.
各 Model 之间是可以相互调用的, Controller 也可以无障碍的调用 Model, 因此将业务逻辑放在 Model 中可以灵活的使用组合的方式复用代码.
而 Controller 之间是不可以相互调用的, 要复用代码只能将代码提升至父类, 通过继承实现, 显然这种做法既不正确, 也不灵活, 因此完全不提倡.
综上所述, 仅仅只是代码复用这一点, 也足以将 "厚 Controller, 薄 Model" 这种不健康的 MVC 思想打入十八层地狱.
现在我们大概知道了代码应该如何分布于 MVC 三层之间, 知其然, 并且也知其所以然. 接下来我们再从另一个角度深刻剖析 MVC, 脱它个精光, 让它赤条条展示在我们眼前.
众所周知, GoF 总结过 23 个设计模式, 这 23 个设计模式是某些特定的编程问题的特效药, 这是业内公认的.
MVC 是一种模式, 但却在 GoF 总结出来的这个 23 个设计模式之外, 确切的说它不是一种设计模式, 它是多种设计模式的组合, 并不仅仅只是一个单独的一个模式.
组成 MVC 的三个模式分别是组合模式, 策咯模式, 观察者模式, MVC 在软件开发中发挥的威力, 最终离不开这三个模式的默契配合. 那些崇尚设计模式无用论的程序员, 请了解只要你们使用 MVC, 就离不开设计模式.
注意, 以下内容以这三个设计模式的知识为基础, 如果对这三个设计模式没概念, 或许会阅读困难.
先说组合模式在 MVC 中扮演什么样的角色.
组合模式只在视图层活动, 视图层的实现用的就是组合模式, 当然, 这里指的实现是底层的实现, 是由编程框架厂商做的事情, 用不着普通程序员插手.
组合模式的类层次结构是树状的, 而我们做 Web 时视图层是 html 页面, html 的结构不正是树状的吗, 这其实就是一个组合模式的应用, 只是浏览器厂商已经把界面相关的工作帮我们做掉了, 但它确确实实是我们应用 MVC 的其中一部分, 只是我们感觉不到罢了, 这也是我们觉得 View 是实现起来最简单最没有歧义的一层的原因.
除网页以外的其他用户界面程序, 如 WPF,Android,Asp.net 等等都是使用树状结构来组织界面控件对象的, 因为组合模式就是从界面设计的通用解决方案总提炼出来的. 所以与其说 MVC 选择了组合模式, 还不如说组合模式是必定会存在 MVC 中的, 因为只要涉及到用户界面, 组合模式就必定存. 事实上即使不理解组合模式, 也不影响程序员正确的使用 MVC, 组合模式本就存在于程序员接触不到的位置.
然而, 观察者模式和策略模式就显得比较重要, 是实实在在 MVC 中接触的到的部分.
观察者模式有两部分组成, 被观察的对象和观察者, 观察者也被称为监听者. 对应到 MVC 中, Model 是被观察的对象, View 是观察者, Model 层一旦发生变化, View 层即被通知更新. View 层和 Model 层互相之间是持有引用的. 我们在开发 Web MVC 程序时, 因为视图层的 html 和 Model 层的业务逻辑之间隔了一个 http, 所以不能显示的进行关联, 但是他们观察者和收听者的关系却没有改变. 当 View 通过 http 提交数据给服务器, 服务器上的 Model 接受到数据执行某些操作, 再通过 http 响应将结果回送给 View,View(浏览器)接受到数据更新界面, 这不正是一个接受到通知并执行更新的行为吗, 是观察者模式的另一种表现形式.
但是, 脱离 Web, 当通过代码去纯粹的表示一个 MVC 结构的时候, View 和 Model 间无疑是观察者和被观察的关系, 是以观察者模式为理论基础的. 即使在 Web 中因为 http 壁垒的原因导致真正的实现有点走样, 但是原理核心和思路哲学却是不变的.
最后是策略模式. 策略模式是 View 和 Controller 之间的关系, Controller 是 View 的一个策略, Controller 对于 View 是可替换的, View 和 Controller 的关系是一对多, 在实际的开发场景中, 也经常会碰到一个 View 被多个 Controller 引用, 这即使策咯模式的一种体现, 只是不那么直观而已.
总结一下, 关于 MVC 各层之间关系所对应的设计模式
View 层, 单独实现了组合模式
Model 层和 View 层, 实现了观察者模式
View 层和 Controller 层, 实现了策咯模式
MVC 就是将这三个设计模式在一起用了, 将这三个设计模式弄明白, MVC 将毫无神秘感可言. 如果不了解这三个设计模式去学习 MVC, 那不管怎么学总归是一知半解, 用的时候也难免不会出想问题.
再次回到最前面讨论的业务逻辑应该放在 Controller 还是 Model 的问题上, 从设计模式的角度讲, 策略模式中的策略通常都很小很薄, 不会包含太多的内容, Controller 是一个策略, 自然不应该在里面放置过多的内容, 否则要替换一个新的会相当麻烦, 与此同时也会破坏 View-Model 的观察者模式, 仿佛 View-Controller 之间即实现了策略模式又实现了观察者模式, 这种混乱是罪恶的根源, 是制造焦油坑让程序员陷入其中无法自拔的罪魁祸首. 切忌, 应当避免.
注: 此文核心思想来自head first 设计模式
来源: https://www.cnblogs.com/aspwebchh/p/8853659.html