APP下载

通用文档程序架构中操作行为的研究与设计

2012-07-25冯灵凯

微型电脑应用 2012年8期
关键词:子类序列化内存

冯灵凯

0 引言

文档应用程序的应用非常广泛,如一般公众使用的Office办公软件套件、各种行业的专业的编辑器等。所以不断有学者对这些应用的相关技术进行了研究,并取得了很多有意义的成果。传统的方法要实现不同的文档类型的应用程序,需要分别开发不同的操作行为接口,不仅工作量大,有重复冗余的工作,而且开发出来的接口很难保持一致,更难于实现接口重用。无法满足同一个框架下的不同文档操作行为必须统一的需求。

本文使用了一种基于模板方法[1]的文档设计模式来定义通用文档程序架构中操作行为。在保证对外暴露统一接口的同时,不同类型的文档又可以有各自不同的隐式行为,同时增加代码复用。

1 国内外研究现状和发展趋势

1.1 研究现状

现在通用文档一般分为两大类:单文档和多文档。对应的框架相应地也可分为:单文档程序框架、多文档程序框架和混合文档程序框架。对应的操作行为相应地也可分为:单文档操作行为、多文档操作行为和混合文档操作行为。而目前对于文档操作行为的国内外的研究现状有二大特点:

(1) 针对单文档操作行为的研究较多,面向多文档操作行为的研究较少。

(2) 在同一个框架下针对只能使用一种文档操作行为的框架研究得比较多(单文档程序框架或多文档程序框架),能同时使用两种文档操作的框架行为研究得较少(混合文档程序框架)。

1.2 发展趋势

综合国内外的研究现状,当前关于通用文档程序架构中操作行为的研究有以下四个发展方向:

(1) 针对统一资源管理下的(如:SVN管理下的)文档操作行为的研究[2]。

由于涉及到文档的共享或独占式占用,在保持服务器端文件的一致性的前提下,提供多用户、一致的交互操作体验。这需要我们提供额外的技术来保证。例如可以从定义统一的资源管理接口上下手,在保持上层调用接口的一致性同时,又可以兼容底下来自不同资源管理者提供的文档管理操作行为服务。

(2) 虚拟单文件下的文档操作行为相统一的研究。

虚拟单文件,就是要求把应用要用到的所有文档都归档为一个单独文件,而这个文件类似于一个压缩包文件形式存在于本地或服务器磁盘上。这样做带来的好处是:保证所有单文件的内部文档结构一致,方便做加解密和版本管理,也提高了加解密和版本管理的效率。因为你只要对单文件进行加解密和版本管理就行了。但是要实现虚拟单文件,还需要很多技术来支撑。例如可以从虚拟文件压缩[3],加解密算法和配置文件管理[4,5]等方面入手。把压缩、加解密和读写配置都封装为底层的服务组件。这样上层应用的操作行为可以不用关心底层具体逻辑实现,更方便实现统一的操作行为。

(3) 对于不同版本文档和不同版本的文档程序,文档操作行为相统一的研究。

就是说当文档和文档程序都有多个版本,且它们之间的版本没有一一对应时,怎么保证文档操作行为的统一。现在当前很多应用对于版本不一致的处理,是根据水桶效应,取它们之间版本最低的那个版本的操作行为来处理的。这会导致:低版本的文档把高版本的文档程序中的最新功能给屏蔽了,或低版本的文档程序把高版本的文档回退到了低版本。没有做到各尽其用。

(4) 对协同编辑操作行为的研究[4]。

2 文档设计模式的提出

模板方法[1],是GOF中的23种设计模式中的一种模式。模板方法:在一个方法中定义一个算法的骨架,而将一些实现步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤,如图1所示:

图1 GOF中的模板方法的类图[1]

基于模板方法的文档设计模式,就是在文档应用框架中定义一簇通用文档程序架构中操作行为的骨架。涉及到行为统一的逻辑处理,都会被放到框架中实现,而对于不同文档操作行为的处理,延迟到对应文档类中来实现。这样使得单文档操作行为和多文档操作行为在UI层上是行为统一的。从而给用户带来一致的交互体验。

3 通用文档程序架构中操作行为的处理原理

通用文档程序中的操作行为难以实现重用和扩展,根本原因是没有把处理逻辑和处理程序有效分离。本文设计了一套基于模板方法的文档设计模式,去帮助通用文档程序的开发人员处理文档程序的通用逻辑,规定通用文档程序的操作行为,然后开发人员可在此基础上实现自己处理逻辑,以此实现通用文档程序架构中操作行为的通用性。

4 通用文档程序架构中操作行为的核心算法

通用文档程序架构中操作行为的核心算法(简称:通用文档算法)是基于模板方法的文档设计模式的一种具体实现,但不仅限于此。

该算法包括框架层核心算法、单文档级核心算法、多文档级核心算法。

4.1 框架层核心算法

考虑一个提供应用类(Application)和文档类(Document)的应用框架。

应用类就是用来处理文档管理操作的。由于通用文档应用程序都会进行新建工程(NewProject)、打开工程(OpenProject)、保存工程(SaveProject)、关闭工程(CloseProject)操作,这些操作,都涉及到处理以外部形式存储的文档和内存中的文档,而其中的关键逻辑是文档的序列化和反序列化。为了保证行为统一,这边使用了模板方法的思路。保证在做真正具体某个操作时,先处理(带Pre的操作)一定出现在处理前,后处理(带Post的操作)一定出现在处理之后。如果不使用通用文档算法,人们就必须在每个子类中分别保证相互的行为统一。不幸的是,人们很容易忘记具体的行为顺序。在你使用了通用文档算法后,你只要在子类中实现要实现的接口,就能保证相互的行为统一。而且编译器能保证你必须事先实现那些接口,不然程序是编译不过的。

新建工程和打开工程都会调用关闭工程,这个也是为了保证行为统一。防止人们在新建工程和打开工程前忘记了关闭先前打开的工程,如图2所示:

图2 文档管理类类图(即应用类类图)

内存文档基类(简称文档基类)是内存中的文档对象的表示,必须是个抽象类。负责具体文档的序列化操作(新建文档OnNew、打开文档OnOpen、保存文档OnSave、关闭文档 OnClose) 、文档的逻辑操作(剪切记录项 Cut、复制记录项 Copy、粘贴记录项 Paste)、文档中某一记录项的操作(新建记录项NewItem、打开记录项OpenItem、 保存记录项 SaveItem、关闭记录项 CloseItem)、对于文档操作的 UI层提示操作(提示用户是否保存当前记录项的修改AskForItemSave、提示用户为新的记录项命名AskForName) 、更新UI操作(根据记录项数据更新UI上控件UpdateUI、控制控件是否可被操作EnableUI等)、文档操作中需要的辅助操作(得到某个记录项GetItem、起一个不重复的记录项名称MakeName等)等的定义或实现。

如图3所示:

图3 文档基类类图

AskForItemSave、AskForName、UpdateUI、MakeName操作都使用了模板方法,对应的单文档子类或多文档子类则必须要实现 SaveItem、GetNameFromUI、ValidateName、OnUpdatUI、EnableUI操作。在内存文档类中为了保证单文档和多文档的在数据层、逻辑层和UI层的操作行为统一,对于文档路径 m_strFilePath的用途也是有不同的含义和解释的,这些在5.2和5.3中会进行阐述。同时为了使单文档与多文档的操作行为保持统一和方便做撤销操作和检测修改标志操作,需要一个临时的记录项m_item来表示当前操作的记录项。

使用通用文档算法构建的具体应用可以通过继承应用类和文档类来满足特定的需求。

4.2 单文档级核心算法

单文档类是文档基类的一个子类。在内存中所有记录项是直接存放在单文档对象中的,而所有记录项序列化时都记录在一个在外部形式存储的文档中。单文档不需要一个记录所有记录项的索引文件。记录项的索引信息和所有记录项的数据信息,在内存中可以通过一个列表的形式进行记录,m_items就实现了这个用途;在外部形式存储的文档中(其路径为 m_strFilePath),则通过文档的结构列表和具体的数据文本信息来表示。

文档的逻辑操作、文档中某一记录项的操作、文档操作中需要的辅助操作中的一些操作(如 GetItem),与多文档不同,都是对内存对象的直接操作,不涉及对数据的序列化操作。

单文档类的实现,如图4所示:

图4 单文档类类图

4.3 多文档级核心算法

多文档类也是文档基类的一个子类。在内存中只有当前记录项是直接存放在多文档对象中的,而所有记录项序列化时都分别记录在各自在外部形式存储的文档中。其实准确地说没有一次对所有记录项进行序列化的操作,序列化操作一次只对单个记录项进行。且多文档必须要有一个记录所有记录项的索引文件(其路径为m_strFilePath),其中记录每一个记录项的名称和记录项对应的文件名。由于这边为了简化算法,记录项的名称和记录项对应的文件名我们用的是同一个。所以记录项的索引信息在内存中,可以通过一个记录项的名称列表的形式进行记录,m_strItemFilePaths就实现了这个用途;在外部形式存储的文档中(其文档路径m_strFilePath),则通过记录名称列表信息来表示。

在多文档中,在OnOpen操作完成之后,在内存中只有记录项的索引信息,不会有所有记录项的数据信息,其实也用不着有,这个是我们有时会选择使用多文档而不使用单文档的原因所在。所以想要得到某一非当前记录项的数据时,必须进行一次序列化操作。而在单文档中,由于所有记录项的数据信息在OnOpen操作完成之后,已经全部序列化读入内存,当想要得到某一非当前记录项的数据时,不用再进行序列化操作了。

文档的逻辑操作、文档中某一记录项的操作、文档操作中需要的辅助操作中的一些操作(如GetItem),与单文档不同,是对在外部形式存储的文档进行操作,涉及对数据的序列化操作。但是由于多文档类和单文档类的基类中(文档基类)使用了模板方法,就会给用户带来一致的操作体验。

多文档类的实现,如图5所示:

图5 多文档类类图

5 代码示例

部分关键操作的伪代码实现,已经在图2、图3、图4、图5中给出。

6 代码示例已知应用

现已经在盛大游戏《零世界》的专业版编辑器中得到运用,且取得不错的效果。在该编辑器中:

对于每个记录项数据多而复杂的模块,采用多文档操作行为。如:场景模块、资源模块等。

对于每个记录项数据少而简单的模块,采用单文档操作行为。如:任务模块、怪物模块、主角模块、物品模块等。

用户在使用编辑器时,完全不会察觉各个模块之间操作有何不同。

其实这边给出的通用文档算法十分通用,几乎可以用在任何一个文档程序中。说不定,你写过的文档程序就已经部分用上了这个算法。

7 结论

本文设计了通用文档算法,对于不同应用类型的文档程序架构中操作行为进行了提炼,解决了操作行为统一的难题。只需要按照已定义的接口编写对应的实现即可,开发效率会有很大提高,而且具有开发简单、可靠性高、重用性强、可读性好、容易操作等优点。若有新类型的文档处理需求,可以通过添加新的单文档或多文档子类来实现;若有新的操作行为需求,可以通过在文档基类添加新的操作行为接口,并在单文档或多文档类中实现之来解决。这对于解决通用文档程序架构中操作行为的一致处理,有可能是一个比较合理的解决方案。

由此可见,研究通用文档程序架构中操作行为,尤其是针对复杂庞大的编辑器,从文档底层的数据操作、文档的逻辑操作、文档的UI层操作3个层面统筹考虑操作行为,具有非常重要的理论与现实意义。

当然通用文档算法还有很多地方需要改进,读者可以从以下几个方面进行深入研究,为文档程序架构中操作行为架构带来更好的、更全面的应用解决方案:

(1) 针对统一资源管理下的(如:SVN管理下的)文档操作行为的研究。

(2) 虚拟单文件下的单文档和多文档操作行为相统一的研究。

(3) 针对协同编辑操作行为的研究。

(4) 剪切、复制、粘贴支持一次操作多个记录项。

(5) 多文档中存放记录项数据的文件名称可以与记录项名称不同。

[1]Erich Gamma, Richard Helm, Ralph Johnson, John Lissides. Design Patterns:Elements of Reusable Object-Oriented software[C]. USA:Addison-Wesley Professional, 1994: 346-352.

[2]孙尚辉, 曹宝香, 王廷蔚. 扩展RBAC模型在文档管理中的应用[J].. 计算机技术与发展, 2007, (3).

[3]刘丽伟, 邓春健. 多文件压缩传输及解压缩的方法[J].武汉理工大学学报(交通科学与工程版), 2009, (6) .

[4]陈丽. 协同编辑系统中并发控制的研究与实现.[j]网络出版年期, 2009, (7).

[5]崔明煜, 刘丽兰, 宋娜, 孙海洋. 协同设计中基于标记文件的版本管理[J].. 机械工程师, 2007, (10).

猜你喜欢

子类序列化内存
卷入Hohlov算子的某解析双单叶函数子类的系数估计
如何建构序列化阅读教学
笔记本内存已经在涨价了,但幅度不大,升级扩容无须等待
“春夏秋冬”的内存
Java类的继承
面向对象的多版本传感器观测服务模式匹配方法
Java反序列化漏洞探析及其修复方法研究
Java 反序列化漏洞研究
内存搭配DDR4、DDR3L还是DDR3?
作文训练微格化、序列化初探