MVC架构模式


详解MVC架构模式

1. 不使用MVC架构模式开发的缺陷

在一个普通的银行转账程序中,通常一个Servlet通常要完成如下的工作

  • 负责数据的接收
  • 负责核心的业务逻辑
  • 负责数据库表中的CRUD操作。
  • 如果使用了jsp技术,那么还要负责页面的展示

缺点

  • 代码的重用性很差,没有进行职能分工,没有独立组件的概念,代码和代码之间耦合度太高
  • 耦合度高,导致代码很难扩展
  • 操作数据库的代码和业务逻辑混杂在一起,编写代码的时候,很难专注于业务代码开发

2. 什么是MVC架构模式

简单来说就是进行分层,让专人做专事,职能分工要明确,这样可以让代码的耦合度降低,扩展力增强

  • M(Model):数据/业务的实际处理。它会将业务结果/数据处理结果交还给控制器。

  • V(View):展示,负责页面展示。接收到实际来自Model的实际数据,直接交接人是Controller,它将数据显示给用户。

  • C(Contoller):核心,是控制器,处理业务/数据的请求分发,起到一个调度的作用。

3. DAO模式简介

DAO:DataAccessObject是数据访问对象,是一种设计模式,属于JavaEE的设计模式,只负责底层数据库表的CRUD,没有任何的业务逻辑。

一般情况下domain中定义的实体类属性类型设置为包装类型(引用数据类型),防止因为null值无法赋给基本数据类型。

一般情况下,一张表对应一个DAO的对象

public interface AccountDAO {
    Integer update(Account account);
    void insert(Account account);
    void deleteById(String id);
    Account selectById(String id);
}
public class AccountDAOImpl implements AccountDAO {
    //jdbc代码暂时为空 
    @Override
    public Integer update(Account account){return 1;}
    @Override
    public void insert(Account account){}
    @Override
    public void deleteById(String id){}
    @Override
    public Account selectById(String id){}
}

4. 基本模式概念

  • pojo:普通简单的对象被称为pojo对象,Plain Ordinary Java Object:简单的Java对象

  • bean:专门数据的对象

  • domain:领域模型对象

  • entity:实体类

实际上都是一种东西

5.Service层

Service:专注于处理相关域业务的一个类模型,在该类中只编写业务代码,希望只专注业务

起名是xxxBiz或者xxxService

public interface AccountService {
    void transfer(String from,String to,Double balance);
}
public class AccountServiceImpl implements AccountService {
    private AccountDAO accountDAO = new AccountDAOImpl();//调用底层的DAO对象执行数据库的增删查改
    @Override
    public void transfer(String from, String to, Double balance) {
        
    }
}

6. MVC架构模式与三层架构的关系

  • 经过上面的DAO层封装和service封装之后,对数据模型进行分发
@WebServlet("/transfer")
public class AccountTransferServlet extends HttpServlet {
    AccountService accountService = new AccountServiceImpl();
    //在这里的话Servlet相当于一个controller
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //负责处理业务分发
        String from = request.getParameter("from");
        String to = request.getParameter("to");
        Double balance = Double.valueOf(request.getParameter("balance"));
        try{
            accountService.transfer(from,to,balance);
            response.getWriter().write(1);//1代表成功,可以用一个Result来封装相关信息
        }catch (Exception e){
            response.getWriter().write(0);
        }finally {
            response.getWriter().close();
        }
    }
}

最终经过上述的分层之后,就形成了这样的项目结构。可以图解为:

Model包含了有pojo ,service,dao

至于表现层/web层包含了有html/css/javascript/Controller(单独一个层)

谈谈你对MVC架构和三层架构的理解

首先MVC架构是基于三个分层的,这三个分层分别是负责请求处理的分发核心层Controller,还有负责业务/数据处理的Model层,还有负责数据/业务处理结果展示的View层。用户发送请求后首先会到达Controller层,Controller层将请求需求分发到Model层进行数据处理,数据处理结束后返回到Controller层,Controller层将数据分发到View层,View将数据进行展示与渲染回显给用户。

至于三层架构,三层架构是基于MVC模式进行的再次划分,对于后端开发需求,将Model层细分为了业务逻辑层数据持久层以及底层数据存储设备DB,对于ControllerView将其划分为了一个层面,也就是表现层或者web层,在三层架构模式认为表现层是直接与用户进行交互的,因此划分为了一个层面。

在后面学习会学习到Spring:它是整个项目的”管家”,它负责项目所有重要对象的创建以及维护对象和对象之间的关系,它并不存在于某一个具体分层中。

7. 分层中的事务控制

事务一定是在service层进行事务的控制的,一般来说是一个方法对应一个完整的事务,因此在业务逻辑执行前开启事务,在业务逻辑结束后提交事务。

同时要注意,如果对象中获取到的connection对象不是同一个connection对象 ,那么事务就是隔离的。两个connection描述对象的执行操作不是同一个配置。

这就好像你两个后端,你两个人都去连接数据库获取connection对象,一个后端想要事务,另一个后端不想要事务,如果是一致配置的话,那就乱套了。

ThreadLocal

1.底层数据结构

在一些业务场景中,我们希望同一个工作线程总能共享一些对象,这些对象应该是跨类的,一种解决思路是提供一个静态的变量,而且为它提供静态访问方法,让其他类来共享这个变量,这样可以解决问题,但是破坏了类的层次结构,也不符合开闭原则。

还有一种做法是提供一个map集合,这个map集合存储在应用上下文之中。这个map的key是Thread对象,value是要存储的共享变量,那么这样做的话,我们就能够在同一个工作线程之中,根据工作线程这个对象来取到对应的存储共享变量。

public class MyThreadLocal {
    //本质原理,实际上还需要考虑多线程访问的问题。
    //所有需要和当前线程绑定的数据都要放到这个容器当中
    Map<Thread,Object> map = new ConcurrentHashMap<>();
    public Object get(){
        return map.get(Thread.currentThread());
    }
    public void set(Object obj){
        map.put(Thread.currentThread(),obj);
    }
    public void remove(){
        map.remove(Thread.currentThread());
    }
}

2. 实现原理

要使用当前线程域的上下文,如果是同一个线程发送请求,那么获取上下文内容肯定是一样的。同时要避免取不到值的问题,这时候需要做一个初始化的特判

Object obj = local.get();
if(obj == null){
    obj = new Object();
    local.set(obj);
}
return obj;

文章作者: 穿山甲
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 穿山甲 !
  目录