软件架构-MVC

    MVC不是设计模式,它是一种软件开发架构模式,包含了很多的设计模式,最为密切是以下三种:Observer (观察者模式), Composite(组合模式)和Strategy(策略模式)。所以说MVC模式又称复合模式。    MVC (Model-View-Controller) 模式的基本思想是数据,显示和处理相分离。模型(Model)负责数据管理,视图(View)负责数据显示,控制器(Controller)负责业务逻辑和响应策略。

    从MVC的形成过程来看,最初只有模型和视图两个元素。模型封装了数据并提供操作接口,视图用来表现数据和接收用户请求。模型是独立的,而视图依赖于模型:从模型获取数据进行显示;向模型发送用户请求,并根据返回结果刷新自己。需要用多个视图表现同一模型时,情况发生了变化:一个视图修改数据以后,不但本身要刷新,其他所有视图也要刷新。如果由该视图通知其他视图,它就需要知道其他所有视图,由于每个视图都可能发出修改,每个视图都要知道其他所有视图,这种关联过于复杂,不但难以维护,而且不便于增加新的视图。如果让模型通知所有视图更新,可能会影响模型的独立性。

    用观察者(Observer)模式 可以解决上述矛盾,从而实现:由模型通知视图,而模型不依赖于具体的视图,具体视图之间相互独立。视图是用户请求的接收者,但不宜作为请求的处理者。因为界面是易变的,如果业务代码和界面代码放在一起,频繁的界面修改可能会破坏比较稳定的业务代码。将业务逻辑分离出来,由一个控制器负责,就是为了避免这种干扰。

    模型在状态变化的时候,直接通知所有视图,视图向模型查询状态数据,然后刷新自身。当用户发出操作时,视图把消息发给控制器,控制器按照业务逻辑进行处理,需要查询或更新数据时,控制器会调用模型。

    MVC架构把数据处理,程序输入输出控制及数据显示分离开来,并且描述了不同部件的对象间的通信方式。使得软件可维护性,可扩展性,灵活性以及封装性大大提高;MVC(Model-View-Controller)把系统的组成分解为M(模型)、 V(视图)、C(控制器)三种部件。视图表示数据在屏幕上的显示。控制器提供处理过程控制,它在模型和视图之间起连接作用。控制器本身不输出任何信息和做任何处理,它只负责把用户的请求转成针对Model的操作,和调用相应的视图来显示Model处理后的数据。

    同样的数据,可以有不同的显示和进行各种处理。显示仅仅是表现数据,而处理是根据用户请求改变数据的过程,不但包含业务逻辑,也要提供响应策略。响应策略由控制器负责,视图可以使用不同的控制器提供不同的响应方式,这是策略(Strategy)模式的应用。


  • Model(模型) - 模型代表一个存取数据的对象。它也可以带有逻辑,在数据变化时更新控制器。

  • View(视图) - 视图代表模型包含的数据的可视化。

  • Controller(控制器) - 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。

  • timg (1).jpg


  •  MVC的优缺点

  • MVC的优点体现在以下几个方面:

  • (1) 有利于团队开发分工协作和质量控制,降低开发成本。

  • (2) 可以为一个模型在运行时同时建立和使用多个视图。变化-传播机制可以确保所有相关的视图及时得到模型数据变化,从而使所有关联的视图和控制器做到行为同步。

  • (3) 视图与控制器的可接插性,允许更换视图和控制器对象,而且可以根据需求动态的打开或关闭、甚至在运行期间进行对象替换。

  • (4) 模型的可移植性。因为模型是独立于视图的,所以可以把一个模型独立地移植到新的平台工作。需要做的只是在新平台上对视图和控制器进行新的修改。

  • (5) 潜在的框架结构。可以基于此模型建立应用程序框架,不仅仅是用在设计界面的设计中。


  • MVC的不足体现在以下几个方面:

  • (1)增加了系统结构和实现的复杂性。对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。

  • (2)视图对模型数据的访问效率低。视图可能需要多次调用Model才能获得足够的显示数据。

  • (3)完全理解MVC并不是很容易。使用MVC需要精心的计划,由于它的内部原理比较复杂,所以需要花费一些时间去思考。同时由于模型和视图要严格的分离,这样也给调试应用程序到来了一定的困难。


  • 举例

  • 对于一个MVC选课网站来说,MVC的是这样划分的:View:jsp页面的表单输入请求会被发送至Controller,jsp页面的java代码块接收来自控制器的数据,并将其显示出来;Controller:Servlet类的doPost方法或doGet方法接收来自jsp的请求,并调用Model的相关方法,查询或更新数据库,并将结果返回给jsp视图;Model:实现对数据库操作的模块。代码举例如下:

  • 视图:login.jsp

  • 登录输入表单,发送请求给控制器
    <form id="loginForm" action="loginServlet" method="post" class="mt-4">
       <div class="form-group mb-4">
          <input type="text" name="username" id="username" placeholder="学号/工号" class="form-control border-0 shadow form-control-lg"/>
       </div>
       <div class="form-group mb-4">
          <input type="password" name="pwd" id="pwd" placeholder="密码" class="form-control border-0 shadow form-control-lg text-violet"/>
       </div>
       <div class="form-group mb-4">
          <div class="custom-control custom-checkbox">
             <input id="customCheck1" type="checkbox" checked class="custom-control-input">
             <label for="customCheck1" class="custom-control-label">记住我</label>
          </div>
       </div>
       <button type="submit" onclick="checkEmpty()" class="btn btn-primary shadow px-5">登录</button>
    </form>
    
    接收来自控制器的数据并表现出来
    <%
    String result=(String)request.getAttribute("result");
    if(result!=null){
      %><div><%=request.getAttribute("result") %></div><%
    }
    %>

控制器:loginServlet.java

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        String name=request.getParameter("username");
        String pwd=request.getParameter("pwd");
        LoginService loginService=new LoginService();
        int state=loginService.login(name,pwd);
        //登录成功
        if(state==0){
            //从Model中查询课表并放入会话中
            ScheduleDaoImpl sdi=new ScheduleDaoImpl();
            List<List<String>> sc=sdi.GetSchedule(name);
            request.getSession().setAttribute("schedule", sc);
            //c从Model中查询学生信息放并放入会话中
            StudentDaoImpl stdi=new StudentDaoImpl();
            List<String> stuList=stdi.GetStudentInf(name);
            request.getSession().setAttribute("student", stuList);

            //页面跳转,返回数据给浏览器
            request.getRequestDispatcher("index.jsp").forward(request, response);
        }
        //登录失败
        else{
            switch (state) {
                case 1:
                    request.setAttribute("result","密码错误");
                    break;
                case 2:
                    request.setAttribute("result","用户名不存在");
                    break;
                case 3:
                    request.setAttribute("result","服务器错误");
                    break;
                case 4:
                    request.setAttribute("result","用户不能为空");
                    break;
                case 5: 
                    request.setAttribute("result","密码不能为空");
                    break;
                default:
                    break;
            }
            request.getRequestDispatcher("login.jsp").forward(request,response);
        }
    }

模型:ScheduleDaoImpl.java

public int DeleteCourse(String studentIdString,String courseIdString) {
        int flag=3;
        Connection conn=null;
        Statement st=null;
        ResultSet rs=null;
        try {
            conn=JDBCUtil.getConnection();
            st = conn.createStatement();
            String sqlString="SELECT * FROM course.schedule where studentId="+studentIdString+" and courseId="+courseIdString;
            System.out.println(sqlString);
            rs = st.executeQuery(sqlString);
            flag=2;//未找到课程
            while(rs.next()){//查询成功
                 String sql="delete from course.schedule where studentId=\'"+studentIdString+"\' and courseId=\'"+courseIdString+"\'";
                int result=st.executeUpdate(sql);
                if(result>0){//删除课程成功
                    flag=0;
                    break;
                }
                else
                    flag=1;//删除添加失败
            }
        } catch (ClassNotFoundException | SQLException ex) {
            Logger.getLogger(CourseDaoImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally{
            JDBCUtil.realeaseJDBC(conn, st,rs);
        }
        return flag;
    }


下面是我和歆歆做的选课网站:

login1.png

index1.png

delete.png


    参考文献

[1]菜鸟教程:MVC模式.https://www.runoob.com/design-pattern/mvc-pattern.html.

[2]徐浩进.详解MVC设计模式.https://www.cnblogs.com/xhj123/p/6170975.html.2016-12-13

首页 所有文章 机器人 计算机视觉 自然语言处理 机器学习 编程随笔 关于