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(控制器) - 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。
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; }
下面是我和歆歆做的选课网站:
参考文献
[1]菜鸟教程:MVC模式.https://www.runoob.com/design-pattern/mvc-pattern.html.
[2]徐浩进.详解MVC设计模式.https://www.cnblogs.com/xhj123/p/6170975.html.2016-12-13