现在的位置: 首页 > 综合 > 正文

EMF.Edit编程学习笔记: Command框架

2013年11月04日 ⁄ 综合 ⁄ 共 3568字 ⁄ 字号 评论关闭

 

FROM:http://www.blogjava.net/eclipshine/archive/2005/07/29/8763.html
(注:大部分翻译,整理自Eclipse Modeling Framework: A Developer's Guide一书的第3.3, 3.4节的内容)

EMFCommand框架分为两个部分,Common Command FrameworkEMF.EditCommandsCommon
Command Framework
定义了基本的Command接口并提供了一些基本的类,例如CommandStack, CompoundCommand等。这个Command框架是非常通用的,并不依赖于EMF.Edit,甚至也不依赖于EMF,是完全独立的一个框架。而EMF.EditCommands,则是专门用来编辑EObjects的。

 
Command接口是所有Command必须实现的基本接口。包括了execute(),undo(), redo()等方法。Command在执行先会先进行测试,执行canExecute()判断其能否被执行。canUndo()被用来检查一个Command是否能被undo(),它返回false也就意味着redo()和undo()没有被实现。Command接口的getResult()和getAffectedObjects()方法是可选的,但是有时候非常有用。getResult()可以用来返回一个执行的结果对象,而getAffertedObjects()方法则可以用来返回在执行的过程中被修改过的对象。通常getAffertedObjects()可以和getResult返回相同的对象,但也并不总是如此。
 
AbstractCommand提供对Command接口的缺省实现。唯一重要的实现是canExecute()方法,将控制流转交给另一个钩子方法prepare()。然而prepare()只被执行一次,而不论canExecute()被执行多少次,这个特性在某些情况下可以避免大量的计算被重复执行。
java 代码
  1. public boolean canExecute() {   
  2.  if (!isPrepared) {   
  3.     isExecutable = prepare();   
  4.     isPrepared = true;   
  5.  }   
  6.  return isExecutable;   
  7. }   

 

CommandStack接口定义了一个Command栈,使用后进先出的方式保存所有执行过的Command,使得undo()和redo()能够被方便的实现。BasicCommandStack是CommandStack接口的一个简单实现。
 
CompoundCommand是一个很有用的类。可以让你通过基本的Command对象来组合更为复杂的高层次的Command。它的execute()方法会依次调用每一个成员Command;而canExecute()等测试方法在当所有成员Command的canExecute()方法返回为true是方返回true。一个有用的技巧是使用appendAndExecute()来加入并立即执行一个Command;使用这个方法可以记录一个命令执行的序列,并一次性的进行undo()。
 
EMF.Edit Commands在Common Command Framework的基础上,执行专门正对于EObject的命令。它定义了如下的几个基本Command:
1.      
SetCommand:用来为EObject的attribute或者reference设置值。
2.      
AddCommand:用来为EObject的multiplicity为many的feature添加一个或者多个值。
3.      
RemoveCommand:则是用来做和AddCommand相反的事情。
4.      
MoveCommand:用来移动对象在multiplicitymanyfeature中的位置。
5.      
ReplaceCommand:用来替换一个multiplicity为many的feature中的对象。
6.      
CopyCommand:执行EObject对象的深度拷贝(Clone).
除了CopyCommand之外,其他的Command均为简单命令,而CopyCommand命令则是由CreateCopyCommand和InitializeCopyCommand这两个命令组合而成。
 
除了上述的基本命令之外,EMF.Edit基于基本命令的,执行High Level编辑功能的命令:
1.      
CreateChildCommand。
2.      
CutToClipboardCommand。
3.      
CopyToClipboardCommand。
4.      
PasteFromClipboardCommand。
5.      
DragAndDropCommand。
 
AbstractOverrideableCommand作为EMF.Edit的Command的抽象基类,上面大部分的命令均继承于它,而AbstractOverrideableCommand则是继承于AbstractCommand。它提供了扩展机制来覆盖其自生的execute()方法:
java 代码
  1. public final void execute() {   
  2.  if (overrideCommand != null)   
  3.     overrideCommand.execute();   
  4.  else  
  5.     doExecute();   
  6. }   

之所以这样做的,而不是直接使用继承来扩展Command原因,是因为你可以使用Common Command来实现模型相关而与EMF无关的Command,来扩展这些专门针对于EMF EObjects的命令。从上面的代码也可以看出,如果要用继承来覆盖已有的命令的话,应该覆盖doExecute()方法而不是execute()方法。

 
通常,Command都是由EditingDomain接口的createCommand(Class commandClass,  CommandParameter commandParameter)来创建的,它接受通用的CommandParater参数,来创建Command。但是,为了方便起见,每一个EMF.Edit Command都提供了static的create()方法来创建相应的对象,而由它在来调用EditingDomain的createCommand()。
 
EditingDomain需要完成三种功能:
1.      
创建commands,在AdapterFactoryEditingDomain中这是通过代理到一个Item Provider来实现的。
2.      
管理Command Undo栈,通过CommandStack来实现。
3.      
提供方法来访问EMF模型对象的ResourceSet,以及load或者save Resource。
 
创建一个对象,一般来说使用的是Command的静态create()方法。例如对于RemoveCommand来说,可以通过如下的代码来创建一个RemoveCommand:
java 代码
  1. Command cmd = RemoveCommand.create(editingDomain,   
  2.                                  aPurchaseOrder,   
  3.                                  poPackage.getPurchaseOrder_Items(),   
  4.                                  aItem);  

 

在EditingDomain的ResourceSet之间存在有双向的关联。因为一个对象知道其Resource,而Resource又知道其ResourceSet,因此,由一个对象可以得到其EditingDomain,而EditingDomain又提供了创建Command的方法,因此一个对象可以在任何地方都能够创建修改这个对象的Command了,如下例所示:

java 代码
  1. EditingDomain editingDomain = getEditingDomain(object);   
  2. editingDomain.getCommandStack().execute(   
  3.  SetCommand.create(editingDomain, object, feature, value));  

抱歉!评论已关闭.