用过Flex的人都知道有个基于MVC的puremvc框架,这个框架因为小巧简单很受欢迎。
PureMVC框架的目标很明确,即把程序分为低耦合的三层:Model、View和Controller。降低模块间的耦合性,各模块如何结合在一起工作对于创建易扩展,易维护的应用程序是非常重要的。在PureMVC实现的经典MVC元设计模式中,这三部分由三个单例模式类管理,分别是Model、View和Controller。三者合称为核心层或核心角色。PureMVC中还有另外一个单例模式类—Facade,Facade提供了与核心层通信的唯一接口,以简化开发复杂度。
这里先放这个PureMVC这张著名的图:
这里就简单介绍了PureMVC一些简单知识,详情可以到puremvc.org 查看。这里我们不大去讲他的原理,只是通过一个例子来简单说下PureMVC的机制如何来运行一个Swing项目。
回到本文重点,因为PureMVC的小巧简单,所以作者也顺带着把他翻译成了C#,ColdFusion,Haxe,Java ,JavaScript ,Objective C ,PHP ,Python ,Ruby,那现在我们就以基于Java来做个Demo来讲讲PureMVC的运行原理。这个例子是一个小型系统的简单实现,首先弹出一个对话框,输入用户名和密码成功后进入系统,进行相关操作,所有动作都是利用PureMvc的机制发送消息,做到MVC的三层Model、View和Controller分离。
由上图知道我们,程序的入口是Facade进去的,这个类是一个单类,一般我们都会继承这个类重写Facade,在程序启动的时候用他我们来注册命令等相关信息。所有的信息发送通过他来发送。在使用的时候我们一般继承他的initializeController方法用于加载初始化的一些Command,比如点击菜单打开一个界面的信息,都是在这里预先注册,如代码:
public class ApplicationFacade extends Facade {
private static ApplicationFacade instance= null;
protected ApplicationFacade(){
super();
}
public static ApplicationFacade getInstance(){
if(instance == null)
instance = new ApplicationFacade();
return instance;
}
@Override
protected void initializeController() {
super.initializeController();
/** *//**
* 注册初始化的Command
* **/
registerCommand(ApplicationConstants.INITSTAR, InitStartCommand.class);
}
/** *//**
* 系统初始化完毕后调用这个发送INITSTAR,监听这个命令的Command
* 就会加载所有的Command
* **/
public void startup(){
sendNotification(ApplicationConstants.INITSTAR, null, null);
}
}
注册完了预加载的Command的命令后,我们的系统初始化完毕后点击一个按钮需要打开一个页面,这个事件就会发送出一个消息,至于发给谁他不管,这其中如果有注册了的Command监听了这个发送的消息,那么他就会做进一步的操作,如图所示:
当这个消息给send出来后,当有Command接受到这个消息后就会做他感兴趣的事。所有的发送消息的方法都是通过sendNotification这个方法发送的这个方法是这样定义的:
public void sendNotification(String arg0, Object arg1, String arg2);
arg0:就是发送的消息,常量字符串,如上面代码的INITSTAR,一般都会放在专门存放常量表中。
arg1:可以存放任何东西,比如要传一些值过去,就可以放在这里面,比如在接下来的登入成功后就会把用户的信息,发送到主界面中去,就可以这样定义:
Map data = new HashMap();
data.put("userName", name);
facade.sendNotification(ApplicationConstants.LOGIN_SUCESS, data, null);
arg2:一般可以为空,或其他什么标识等。
当发送完一个命令对应的Command监听到,他会在一个execute方法中做出相应的操作如:
@Override
public void execute(INotification noti) {
super.execute(noti);
if(ApplicationConstants.SHOW_FRAME_01.equals(noti.getName())){
//打开InternalFrame01
doShow01();
}else if(ApplicationConstants.SHOW_FRAME_02.equals(noti.getName())){
//打开InternalFrame02
doShow02();
}
}
当侦听到一个命令比如执行doShow01打开一个页面,这个页面如果需要和其他页面有消息接发的时候,那么在这里就主要注册一个Mediator,这个Mediator要重写两个方法,
public String[] listNotificationInterests( ){
return new String[]{
ApplicationConstants.LOGIN_SUCESS,
ApplicationConstants.CREATE_FRAME,
ApplicationConstants.EXIT,
ApplicationConstants.SEND_TO_FRAME_01,
ApplicationConstants.SEND_TO_FRAME_02
};
}
这个listNotificationInterests方法注册我要监听什么消息。
还一个handleNotification方法如:
public void handleNotification(INotification noti) {
// TODO Auto-generated method stub
super.handleNotification(noti);
if(ApplicationConstants.LOGIN_SUCESS.equals(noti.getName()))
doLoginSucess(noti);
}
}
这个handleNotification方法,是执行监听到那些消息后执行具体的动作。也就说一个命令发送会有Command和Mediator都接受到。大致这个框架就是这样处理的。
通过上面的介绍,我们就结合一个例子来简单实现下,这个例子大意是程序启动后出现一个登入框,任意输入用户名和密码点击登入,就会发送一个消息LOGIN_SUCESS,那么这主界面对应的MainFrameMediator监听到这消息就会显示出程序的主界面,这个主界面的效果图为
其中点击菜单栏的Frame01就会出现标题栏为:Kissjava的一个JinternalFrame,点击Frame02会出现一个标题栏为Rocky Jiang的JinternalFrame,在标题栏为Kissjava页面中的输入框中输入一些信息点击发送一个SEND_TO_FRAME_02消息,这个消息会有对应的标题栏为Rocky Jiang的页面对应的Mediator和主界面的Mediator监听到。所以在各自对应的日志输入框中都会出现对应的消息。刚兴趣的人可以在后面提供的链接下载代码自己运行看看。代码结构简单。
使用PureMVC机制,可以很好的实现MVC三层很好的分离,在本例子中由于例子简单就没涉及到Model层,这个Model它只负责有数据更改的时候发送消息,但不会接受消息,这样才能做到更好的分离。
当然使用这个还涉及到一些不用的对象销毁等问题,这里就不详说了。
源代码下载:DOWNLOAD