2.1.2-mvc.md 5.8 KB

MVC

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

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

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

|____mappers
|____model
|____service
|____utils
|____controller

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

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

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

public String getUserName() {
    return userName;
}

public void setUserName(String userName) {
    this.userName = userName;
}

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

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

在多数时候,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代码:

<html>
<head><title>First JSP</title></head>
<body>
  <%
    double num = Math.random();
    if (num > 0.95) {
  %>
      <h2>You'll have a luck day!</h2><p>(<%= num %>)</p>
  <%
    } else {
  %>
      <h2>Well, life goes on ... </h2><p>(<%= num %>)</p>
  <%
    }
  %>
  <a href="<%= request.getRequestURI() %>"><h3>Try Again</h3></a>
</body>
</html>

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

<div class="information pure-g">
    {{#.}}
    <div class="pure-u-1 ">
        <div class="l-box">
            <h3 class="information-head"><a href="#/blog/{{slug}}" alt="{{title}}">{{title}}</a></h3>
            <p>
                发布时间:<span>{{created}}</span>
            <p>
                {{{content}}}
            </p>

            </p>
        </div>
    </div>
    {{/.}}
</div>

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

###Controller

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

###更多

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

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

####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模式。