MVC

人们在不断地反思这其中复杂的过程,整理了一些好的架构模式,其中不得不提到的是我司 Martin Fowler 的《企业应用架构模式》。该书中文译版出版的时候是2004年,那时对于系统的分层是

层次 职责
表现层 提供服务、显示信息、用户请求、HTTP请求和命令行调用。
领域层 逻辑处理,系统中真正的核心。
数据层 与数据库、消息系统、事物管理器和其他软件包通讯。

化身于当时最流行的 Spring,就是 MVC。人们有了 iBatis 这样的数据持久层框架,即 ORM,对象关系映射。于是,你的 package 就会有这样的几个文件夹:

  1. |____mappers
  2. |____model
  3. |____service
  4. |____utils
  5. |____controller

在 mappers 这一层,我们所做的莫过于如下所示的数据库相关查询:

  1. @Insert(
  2. "INSERT INTO users(username, password, enabled) " +
  3. "VALUES (#{userName}, #{passwordHash}, #{enabled})"
  4. )
  5. @Options(keyProperty = "id", keyColumn = "id", useGeneratedKeys = true)
  6. void insert(User user);

model 文件夹和 mappers 文件夹都是数据层的一部分,只是两者间的职责不同,如:

  1. public String getUserName() {
  2. return userName;
  3. }
  4. public void setUserName(String userName) {
  5. this.userName = userName;
  6. }

而他们最后都需要在 Controller,又或者称为 ModelAndView 中处理:

  1. @RequestMapping(value = {"/disableUser"}, method = RequestMethod.POST)
  2. public ModelAndView processUserDisable(HttpServletRequest request, ModelMap model) {
  3. String userName = request.getParameter("userName");
  4. User user = userService.getByUsername(userName);
  5. userService.disable(user);
  6. Map<String,User> map = new HashMap<String,User>();
  7. Map <User,String> usersWithRoles= userService.getAllUsersWithRole();
  8. model.put("usersWithRoles",usersWithRoles);
  9. return new ModelAndView("redirect:users",map);
  10. }

在多数时候,Controller 不应该直接与数据层的一部分,而将业务逻辑放在 Controller 层又是一种错误,这时就有了 Service 层,如下图:

Service MVC

Domain(业务)是一个相当复杂的层级,这里是业务的核心。一个合理的 Controller 只应该做自己应该做的事,它不应该处理业务相关的代码:

我们在 Controller 层应该做的事是:

  1. 处理请求的参数
  2. 渲染和重定向
  3. 选择 Model 和 Service
  4. 处理 Session 和 Cookies

业务是善变的,昨天我们可能还在和对手竞争谁先推出新功能,但是今天可能已经合并了。我们很难预见业务变化,但是我们应该能预见 Controller 是不容易变化的。在一些设计里面,这种模式就是 Command 模式。

Model

模型用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。

它是介于数据与控制器之间的层级,拥有对数据直接访问的权力——增删改查(CRUD)。Web 应用中,数据通常是由数据库来存储,有时也会用搜索引擎来存储

因此在实现这个层级与数据库交互时,可以使用 SQL 语句,也可以使用 ORM 框架。

SQL(Structured Query Language,即结构化查询语言), 语句是数据库的查询语言

ORM(Object Relational Mapping),即对象关系映射,主要是将数据库中的关系数据映射称为程序中的对象。

View

View 层在 Web 应用中,一般是使用模板引擎装载对应 HTML。如下所示的是一段 JSP 代码:

  1. <html>
  2. <head><title>First JSP</title></head>
  3. <body>
  4. <%
  5. double num = Math.random();
  6. if (num > 0.95) {
  7. %>
  8. <h2>You'll have a luck day!</h2><p>(<%= num %>)</p>
  9. <%
  10. } else {
  11. %>
  12. <h2>Well, life goes on ... </h2><p>(<%= num %>)</p>
  13. <%
  14. }
  15. %>
  16. <a href="<%= request.getRequestURI() %>"><h3>Try Again</h3></a>
  17. </body>
  18. </html>

上面的 JSP 代码在经过程序解析、处理后,会变成相对应的 HTML。而我们可以发现在这里的 View 层不仅仅只有模板的作用,还加入了部分的逻辑。我们可以在后面细细看这些问题,对于前端的 View 层来说,它可能是这样的:

  1. <div class="information pure-g">
  2. {{#.}}
  3. <div class="pure-u-1 ">
  4. <div class="l-box">
  5. <h3 class="information-head"><a href="#/blog/{{slug}}" alt="{{title}}">{{title}}</a></h3>
  6. <p>
  7. 发布时间:<span>{{created}}</span>
  8. <p>
  9. {{{content}}}
  10. </p>
  11. </p>
  12. </div>
  13. </div>
  14. {{/.}}
  15. </div>

在这里的 View 层只是单纯的一个显示作用,这也是我们推荐的做法。业务逻辑应该尽可能的放置于业务层。

Controller

控制器层起到不同层面间的组织作用,用于控制应用程序的流程。

更多

在前后端解耦合的系统中,通常系统的架构模式就变成了 MVP,又或者是 MVVM。

MVC、MVVM、MVP 对比

三者间很大的不同在于层级间的通讯模型、使用场景。

MVP

MVP 是从经典的模式 MVC 演变而来,它们的基本思想有相通的地方:Controller/Presenter 负责逻辑的处理,Model 提供数据,View 负责显示。

MVVM

MVVM 是 Model-View-ViewModel 的简写。相比于MVC悠久的历史来说,MVVM 是一个相当新的架构,它最早于2005年被由的 WPF 和Silverlight 的架构师 John Gossman 提出,并且应用在微软的软件开发中。而 MVC 已经被提出了二十多年了,可见两者出现的年代差别有多大。

MVVM 在使用当中,通常还会利用双向绑定技术,使得 Model 变化时,ViewModel 会自动更新,而 ViewModel 变化时,View 也会自动变化。所以,MVVM 模式有些时候又被称作:model-view-binder 模式。