1、 最初的程序都是是命令行界面,后来进化到GUI(Graphic User Interface),即图形化用户接口。以一个计算器软件为例,一个程序无论C/S还是B/S结构都需要搞定:
a) 界面布局。整个计算器界面要怎么布局看起来才合理、美观。
b) 业务逻辑。例如用户点击“=”按钮时,根据输入计算输出结果。
c) 界面交互。例如用户点击“=“按钮后,界面有什么响应,如显示结果以及结果显示位置等。
无MVC的情况,如winform在一个Form中,即有计算器的界面显示代码,也有触发监听器后的流程控制逻辑,还有功能逻辑计算代码,这三者搅合在一起,程序复杂了后,代码长度惊人,修改、扩展、阅读他人代码都是问题。
2、 桌面GUI程序的MVC设计模式。
符合“低耦合,高内聚“的软件工程理念。表现在哪里?在于MVC将界面显示代码跟业务逻辑代码有效隔离,将原先糅杂一起的代码分开,各部分趋于专门化,功能职责单一。这样让程序更易阅读、维护、扩展了。
a) View:负责界面显示。
b) Controller:负责View、Model、Service之间的交互、控制业务流程。不涉及具体的业务功能代码。在桌面端Controller可以是组件监听器的匿名实现类。
c) Model:简单的数据模型,封装View中的数据,以便于在其他层中的传递和使用(以对象的形式)。是数据模型,并不是业务模型,也不涉及具体的业务功能代码。
d) Service:封装了业务逻辑,专门实现业务功能的,如程序功能实现、数据库操作、第三方库调用等。在这里专门把Service标注出来,是为了强调Model仅仅是数据模型,Controller是流程控制,他们都不含业务功能代码,业务功能代码集中在Service层。
桌面MVC的实现。MVC把界面显示集中在View层,功能实现放在Service层,再在他们间封装出Model以便数据共享,和Controller层调和各层的交互及流程控制。这样,就实现了显示与业务的分离。
1) View与Model应用观察者设计模式,一方面View从Model中获取数据渲染后呈现给用户,另一方面当Model被修改后能自动刷新到View中并显示出来。
2) View与Controller可以应用策咯模式,增加程序灵活性。
3) Controller组合Service(面向接口)和Model。
一个java Swing使用MVC的例子:
public abstract class View{ public void update(); } public class ViewImpl extends View{ //View的界面元素属性。 Model model;//应用观察者模式 Controller controller;//组合,可以用策略模式
public ViewImpl(){ model = new ModelImpl(this); controller = new Controller(model) //界面布局方法调用,初始化组件方法调用(用model中数据) }
xxx.addActionListener(new actionlistener{ @Override public void actionPerform(){ //将界面组件数据刷新到model中 controller.do1(); } })
@Override public void update(){ //更新model中的数据到View的界面组件中。 }
}
public interface Controller{ public void do1(); public void do2(); public void do3(); } public class ControllerImpl implements Controler{ Model model; public Controler(Model m){ model = m; } @Override public void do1(){ //从model对象获取数据 //执行业务逻辑和流程 //结果更新到model ////其他一些功能调用和流程控制。 model.notifyView(); } }
public interface Model{ public void notifyView(); } public class ModelImpl{ //模型属性等 View view; public ModelImp(View v){ view = v; } public void notifyView(){ view.update(); } }
public class Application{ public static void main(String[] args){ //用户登陆及验证通过后 View viewImpl = new ViewImpl(); view.visable=true; } }
目录结构:这样,1)符合面向接口编程(Controller和Model)和面向抽象编程(View),将设计与实现分离。2)每一个Form都由View、Controller、Model三个文件组成,功能划分清晰,职责单一,便于开发维护。 |-Form |-View.java |-Controller.java |-Model.java |-ViewImpl_1 |-ViewImpl.java |-ControllerImpl.java |-ModelImpl.java |-ViewImpl_2 |-ViewImpl_3 |-Service |-Dao |-DBUtilies.java |-UserDao.java |-Impl |-UserDaoImpl.java |-entity |-user.java 思考:MVC只是一个设计思想,实现方式多样。 1)上面这种方式,每一个页面从原来的糅合一起到划分成三个页面,让职责单一,便于开发维护。但很明显额外多出很多文件出来,当程序规模不大时是否还要这样一分为三? 2)上面View与Controller,Controller与Model他们之间是组合关系,是否可用策略模式,让View根据不同情况使用不同Controller? 3)上面通过View的监听器的作用只是调用Controller,真正的流程控制、功能调用在Controler中实现,可不可以直接用监听器的匿名实现类做Controller,而减少额外的Controller文件?那么考虑用Controller类做监听器的实现类又如何呢? 4)创建对象的方式,是否考虑工厂设计模式,进一步解耦?还有可见性的问题,Controller只可见Model和Service,那要控制View的状态怎么办,是否需要封装其他工具类?这些问题用Spring Ioc解决怎么样?还有dao模块用Mybatis怎么样? 5)Controller中既要处理功能调用又要处理页面交互,一般可以单线程,先控制功能调用,调用后把结果存到Model,最后控制View显示界面和model数据。可不可以多线程,可不可以把功能调用和页面交互异步处理?那又是否需要同步呢? |
3、 web端程序的MVC模式。
后来B/S结构的程序开始慢慢发展,从静态网页到动态网页。先说不使用MVC设计模式的情况,如java ee中,仅用jsp做开发。那么一个jsp页面中即有html、css、js组成的可视化界面显示,还有流程控制代码,以及访问数据库等的java程序片。为了解决开发的复杂性,同样在B/S中使用MVC设计模式。
(典型的jsp+servlet+javaBean实现MVC)
web的MVC模式与桌面端MVC原理一样,不过在实现上有很大不同,特别是Model层了。两者的Model层在功能上是一样的,都是简单的封装对象。
实现上,前面说过桌面端View与Model是观察者模式,View从Model中获取数据渲染后呈现给用户,同时当Model被修改后能自动刷新到View中并显示出来。而web端MVC中是依赖容器对javaBean组件的支持。jsp和Servlet中按规则使用javaBean,web容器提供一致性支持,servlet修改javaBean的属性后,当响应用户jsp页面时,从javaBean组件中渲染数据到页面并翻译成html返回。
有两个问题:1)、javaBean的使用方式。直接使用,jsp页面用<jsp:UseBean />标签,servlet用new操作符。间接使用,还可以通过内置对象Request等传输。这两种方式依然归于上面Model,因为它的本质没变。
2)、从本文开始到现在,我还是认为MVC中的Model只是简单的数据模型,而不是有的博客上说的jsp做界面,servlet做流程控制,javaBean处理业务逻辑。MVC本质上是为了解耦界面显示(如jsp)与业务逻辑(如service),独立出Controller控制流程和各层的交互,再添一个Model层解耦View和Controller。
4、 其他MVC开发框架SpringMVC
上面javaEE原生组件jsp+serlet+javaBean已经可以用MVC模式开发web程序。那为什么大多后台开发都用SpringMVC、Struts2这些开发框架呢?
1) javaEE原生组件虽然对程序开发提供了支持,但面对现在多变的需求,开发过程繁杂,重复代码多。而SpringMVC等提供了封装更好的组件与环境支持,能更快、更简洁用于程序开发。从上面明显看出,组件间耦合性更低了。特别是通过springMVC把View层和其他层分离,让程序真正前后端分离了。
2) springMVC框架提供了更灵活的程序架构,更适应现在程序开发的多变。如不止可以响应用户jsp页面,还可以返回json、xml、excel、pdf等。
3) SpringMVC框架,还可以自由地选择与其他框架搭配整合,如spring、mybatis等,对程序的开发提供更好的支持。
4) 框架本身,支持为特定程序架构定制组件,程序设计将有更多可能。如根据框架提供的接口,用户可以自定义HanderAdapter、ViewResolver等组件,以此为Controller、View的变化提供支持。
5、 MVC的衍生------MVP模式
MVC有效的降低了界面显示层与业务逻辑层的耦合性,准确的说是web端的MVC模式,对于桌面端来说,MVC实现起来有点复杂,View同时依赖Controller和Model,特别是View-Model用观察者模式实现了。MVP由MVC演变而来,但还是有很大区别:
1) view更新方式不同。MVC中是通过策咯模式,由Model调用View的接口刷新,因此View就要依赖Model。MVP中View只依赖Presenter,由Presenter调用View的接口刷新。
2) MVC的Model是数据模型,只是简单的数据封装。而MVP中的Model是业务模型。此Model非彼Model,这点是最让人迷糊的了,但要分清,所以上图用Model(service)。
6、 MVC的衍生------MVVM模式
MVVP同样由MVC演化而来,MVVM与MVP有点类似,不过View的刷新是通过“数据绑定”。很典型的一种实现:前端js框架VUE:
1) 通过事件驱动,把显示层大的用户操作传递到js逻辑层
2) js执行逻辑处理后,修改data域
3) data域和显示层html是绑定了的,所以自动把结果刷新到显示层html
7、 总结
不论桌面端还是web端,一次程序交互可以抽象为:
1)请求:桌面端通过事件监听提交;web前端通过事件驱动提交给js逻辑层;后端通过http、https、web service等协议接受。
2)处理:控制器调用接口处理业务逻辑,以及整个操作流程的统筹控制。
3)响应:响应内容包括页面和数据,有可能只有页面如静态网页,也有可能只有数据如json。
各种模式主要区别从上面第3步总结——响应:
桌面端MVC,是用观察者模式实现,由Model调用View的接口刷新界面。
web端MVC,是通过web容器、SpringMVC等三方库的支持,将Modle渲染到View再返回给用户显示。
MVP模式,多用于桌面端或安卓等开发,由Presenter调用View的接口刷新界面。
MVVM模式,多用于web前端开发,通过数据绑定刷新页面数据。