Gef与MVC体系结构

摘要:本文首先介绍了标准的MVC体系构架,同时也介绍了最常见的一类综上所述,在gef框架中,用户编辑请求的相应过程如下MVC模式的变种。之后,文章重点介绍了MVC结构在gef框架中的体现与应用,以及gef是如何综合利用工厂模式、命令模式等设计模式来辅助MVC结构的实现。例如gef成功利用命令模式分担了控制器的部分责任。
前言
GEF全称Graphical Editor Framework。它是一个基于eclipse的图形化编辑框架。通过它,开发人员可以方便的以图形化的方式(而非文本的方式)展示和编辑模型。GEF是一种很有价值的工具,很多著名的应用都采用了gef框架,其中包括现在最流行的开源工作流jbpm的定制工具。Gef是按照标准的mvc模式实现的,其中还使用到了工厂模式、命令模式,Policy模式等一些设计模式。
MVC结构
MVC是"Model-View-Controller"的缩写,即”模式-视图-控制器"。MVC结构强制将一个应用分为模型层、视图层以及控制器。通过三者之间的协调共同响应完成用户的请求,即交互过程。
它们之间的协作关系如图:



上图为mvc模式最标准也是最常见的一种形态。从上图可以看出,模型与视图不直接打交道,而是通过控制器,即控制器完全分离了视图与模型。这是mvc模式的最大特点之一。
在现实开发中,由于实际需要,开发设计人员通常会对标准的mvc模式进行一些修改。屏弃其中的某些特性,而加入新的特性。其中最常见的变化形式如下图所示:



可以看到,控制器并没有完全分离视图与模型。即它不再负责根据模型修改视图,这一过程是让模型与视图双方“面对面”直接进行。这样做虽然增强了视图与模型之间的耦合,但是减轻了控制器的负担。
另外,在通常情况下,为了进一步解耦合,层与层之间的数据通过一种叫做DTO即数据传输对象的介质进行传递。DTO的时间通常很简单,只有若干属性和属性对应的get/set方法,是一个标准的纯java对象,即pojo。例如基于mvc结构的struts中的actionFrom即为一个DTO。
视图
视图层的作用主要有两个:
 接收用户输入,将输入信息传递给控制层。
 负责展示数据,它将模型层中的具体数据以一定的形式展示给用户。
模型和视图之间是一个多对多的关系,一个模型可以对应多个视图,一个视图也可以关联多个模型。
控制器
控制层接收到视图层传递过来的请求后,分析请求信息,根据请求内容选择相应的模型,并修改模型的具体数值。
同时当模型发生变化的时候,将会通知控制器,以更新视图。
模型
模型是行为与状态的双重抽象,即封装了数据与方法。当模型发生变化时,相应的视图会根据新的模型数据重新绘制展现内容。
优点
使用mvc结构的应用有如下有点:
 便于分工。Mvc机构将程序分为’M-V-C’三层,这三层各司其职。这样便于分工协作。例如,传统结构的应用将业务逻辑和界面显示混杂在一起,这样美工很难对页面进行美化。而mvc结构的应用,将应用分层,视图层只有展现代码便于美工美化页面。
 提高了代码的可重用性。多个视图能共享一个模型,多个模型也能共享一个视图,提高了代码的可重用性。
 便于维护更新,由于mvc的解耦合特性。使得维护和变更相对变得比较容易。因此可以方便地改变应用程序的业务数据和业务规则,迁移数据库等等。不会牵一发而动全身。
Gef中的mvc实现
Gef完全按照标准的mvc体系结构完成。
模型
Gef模型的规约十分宽泛——任何java类都可以作为gef的模型。也就是说,gef在模型层是非侵入式的。这一点使得gef的应用更加广泛,灵活。
但是为了能够让控制器知道模型的变化,我们需要一种机制——让模型发生变化的时候通知控制器。由于灵活性的需要,gef并没有把这种机制实现在框架层。但是我们通常会在模型层中添加PropertyChangeSupport类型的成员变量,用来触发事件,通知控制器。例如:
public class AbstractModel {
private PropertyChangeSupport listeners = new PropertyChangeSupport(this);
public void addPropertyChangeListener(PropertyChangeListener listener) {
listeners.addPropertyChangeListener(listener);
}
public void firePropertyChange(String propName, Object oldVal, Object newVal) {
listeners.firePropertyChange(propName, oldVal, newVal);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
listeners.removePropertyChangeListener(listener);
}
}
视图
视图是模型图形方式的表现,它以某种方式展示模型。Gef是一个图形编辑框架,所以gef的视图主要是将模型以图形化的方式显示出来。虽然任何实现IFigure接口的类都可以作为视图,但是GEF使用Draw2D可视图形(figure)。Draw2d是SWT平台上的图形库,你可以用它定制属于自己的、不依赖于特定操作系统本地组件的上层组件。
那么视图又是如何显示的呢。这要用到AbstractEditPartViewer,它负责将视图安装到同一个SWT Control上。
控制器
在gef中,控制器又称为编辑部件,是模型和视图之间的桥梁,也是gef最重要的部分。所有的Gef控制器都需要继承EditPart类。
根据mvc体系结构,控制器的功能主要有两个。
 监听模型的变化,根据变化修改视图。
 当用户编辑视图时,把编辑的结果反映到对应得模型中。
创建——工厂模式
Gef在控制器的生成中,使用了工厂模式。通常每一个模型都对应一个控制器,所以gef要求提供一个EditPartFactory,该对象负责通过给定的模型创建与之对应的控制器。
当模型被创建的时候,EditPartFactory将会被调用,创建出模型对应的控制器。
监听模型变化
控制器需要监听模型的变化,从而根据新的模型数据重新显示视图。那么就需要将控制器注册成为模型的监听者。例如下面的代码
public void activate() {
if (isActive()) {
return;
}
super.activate();
((Node) getModel()).addPropertyChangeListener(this);
}
public void deactivate() {
if (!isActive()) {
return;
}
super.deactivate();
((Node) getModel()).removePropertyChangeListener(this);
}
方法activate的作用是当被激活的时候,把自己注册成为模型的监听。Deactivate相反,当失活的时候,将自己从对应的模型的监听者中删除。
由于模型层使用了PropertyChangeSupport类,所以,控制器需要实现PropertyChangeListener接口。PropertyChangeListener要求实现propertyChange方法。
public interface PropertyChangeListener extends java.util.EventListener {
void propertyChange(PropertyChangeEvent evt);
}
当模型发生变化时,对应控制器的propertyChange方法将会被调用。要说明的是,在gef应用中,控制器通常负责根据模型数据修改视图显示,而非简单的通知视图重画。
修改模型——策略与命令
当用户进行编辑操作的时候,控制器还需要解析这些操作并修改相应的模型。这通常是一系列负责的操作,可能会使得控制器非常庞大。Gef通过进入请求编辑策略与命令模式很好大分担了控制器的本身的负担。也达到了解耦合的目的。其中编辑策略用于解析用户编辑请求,命令用于修改模型。
同时引入命令模式的另外一个目的就是“回退”功能,一个好的图形编辑器“回退”功能是必不可少的。命令模式通过“redo”和“undo”等操作可以很多好的支持“重做”以及“回退”的功能。
当控制器接收到用户的编辑请求后,会根据请求对象中的角色信息寻找处理该请求的编辑策略。要说明的是,编辑策略需要事先被注册安装到控制器中,并对应相应的角色。角色是gef框架抽象出来的一个标识。控制器EditPart就是通过角色标识找到处理请求的策略的。
编辑策略接收到请求后,分析请求信息。根据分析的结果选择创建相应的命令,并且初始化命令的相关参数。
由gef框架负责执行编辑策略产生的命令。命令将会修改相应的模型。同时gef框架会记录下执行的命令,以备“重做”“后退”等功能使用。
用户编辑请求响应过程
综上所述,在gef框架中,用户编辑请求的相应过程如下:


1. 当用户进行编辑操作时,gef框架将操作封装成一个请求对象,并将其传递给控制器。
2. 控制器根据角色选择相应的编辑策略处理请求。
3. 编辑策略分析请求数据,创建并初始化命令对象。
4. 命令执行的过程就是修改模型的过程。
5. 当模型被修改后,将会触发事件,告知其监听者——该模型对应的控制器。
6. 控制器根据模型数据修改视图显示。
结束语
Gef是一个完全基于MVC体系构架搭建的图形编辑框架。正是MVC体系构架的进入,使得模型层与视图层解耦合。那么模型层的约束就得到了极大的解放。这意味着gef可以适用于更广泛的业务。也正是MVC体系结构的进入,使得基于gef框架开发的应用结构更加清晰,更加有利于分工开发与后期维护。
同时gef引入了请求编辑策略与命令模式成功分解了gef控制层的负担。其中命令模式的引入也使得应用支持“重做”“回退”等功能。