分布式铁路车辆分布组件的设计与实现

2014-11-30 07:48孙学波李昕妍
计算机工程与设计 2014年1期
关键词:列表队列双向

孙学波,李昕妍

(辽宁科技大学 软件学院,辽宁 鞍山114051)

0 引 言

目前,应用组件开发应用软件已经成为主流的软件开发方法[1]。当前流行的各种软件开发架构体系,如 Microsoft Visual Studio.Net和Eclipse等,均提供了大量的可复用的软件组件,以支持各种应用软件的开发。应用现有组件不仅可以有效地降低软件开发的难度,而且也有利于提高软件开发的效率和质量。这些软件组件基本能够满足大部分应用领域的功能需求,如基于数据库的管理信息系统领域等。但对于某些特殊的应用领域,却无法找到合适的软件组件来满足这些特殊的需求。因此,独自开发满足这些特殊需求的可复用的软件组件就成为一件十分有意义的事了[2-5]。

在铁路运输管理系统[6-8]项目中,我们遇到了一个需要提供车辆分布的可视化表示和交互式地进行车辆调度作业的特殊需求。为更好地支持这一需求,我们提出了一个基于多队列[9]的分布式铁路车辆分布可视组件的概念,并给出了其具体的设计与实现。应用这个组件成功地解决了项目中的车辆分布的可视化问题和车辆调度作业问题。

1 基本概念

为完整地描述组件的逻辑结构,首先给出与本组件相关的一些基本概念。

队列元素:本文中的队列元素是指一个实现了某个特定接口的实体对象,用于描述现实世界中的某个客观实体。在应用实例中,用于表示铁路车辆实体。队列元素所在的队列为其所处的某种”环境”,其特殊性在于元素与其所处的环境之间存在某种顺序和位置上的关联或约束。

本文强调以下两种约束:

(1)位置约束:每一个队列元素在其所在的队列中均具有一个位置属性,这个位置不一定决定于元素本身的属性,它可能更多地决定于人对与队列元素对应的客观实体的管理 (如车辆在股道上的位置或货物在货位上的位置)。显然这个属性是可以并且需要被改变的。

(2)接口约束:为实现对队列元素实施有效的管理,就需要在组件内部对队列元素定义一系列操作,同时又希望这些操作与队列元素实体的具体属性无关。因此本组件仅为队列元素定义了一个抽象类,从而省掉了其对应实体类的具体实现,其具体实现则留到其具体的应用中。

队列:所谓队列是一个由队列元素构成的线性表,其插入操作限制在表的一端进行,而删除则限制在表的另一端进行。队列的操作则包括初始化、进队、出队、判断队列是否空、取队列元素和队列的可视化等。

双向队列:所谓双向对列是一个由队列元素组成的线性表。其插入和删除操作则限制在队列的两端进行。双向队列的操作与队列操作基本相同,不同的是仅仅放宽了对插入和删除位置的限制。一个双向队列用于表示现实世界中的某个实体或实体集,如在本项目案例中,表示一条“股道”。显然,双向队列仅是对队列概念的一个扩充。

多重双向队列[9]:所谓的多重双向队列是一个由若干个双向队列组合而成的一个集合。也可以说多重双向队列是一组实现了某个特定接口的对象构成的集合,这些对象分布在若干个双向队列中,而所谓的多重双向队列就是由这样一组多重双向队列聚合而成的一个对象。

多重双向队列的实质是一组由多个双向队列构成的集合,它对应于现实世界中的某个特定的实体或实体集。如果一个队列表示某调车场里面的一条股道,那么,这个队列则对应了一个实体集 (一组车辆),它也对应了一个特定的实体股道。而一个队列集合则可以表示一个或多个调车场 (此时也可以称为作业区)。此时则更容易理解,多重双向队列概念所具有的现实意义。

多重双向队列从概念上来说是一组双向队列构成的集合,它实际上是现实世界中一组逻辑相关的有序元素集合构成的集合。元素在某个队列中的相对位置则描述了元素与元素、元素与队列以及元素与多重双向队列之间的相对关系。

所以,多重双向队列上的操作就应该是以特定方式描述、展现和维护它们之间的关系的一组操作集合。

本组件定义的多重双向队列的主要操作如下:

(1)初始化:初始化多重双向队列,计算每个双向队列的大小、显示位置等数据。初始化每个双向队列对象。

(2)可视化:显示每一个双重队列的可视属性及其队列中的元素。

(3)修改队列元素:用于修改指定元素的实体属性。

(4)生成队列操作命令列表:与用户交互编制用于在不同队列间转移元素的 “队列操作命令列表”。

(5)执行队列操作命令列表:执行当前的队列操作命令列表,修改队列元素位置。

多重队列操作:首先,把某个双向队列的一个入队或出队操作称作一个队列操作命令。其次,把一组逻辑上相关的队列操作命令称为一个多重队列操作。显然,一个多重队列操作实际上就是车辆调度系统中的一个调车作业计划,它可用于实施一次车辆调度作业。

例如要将第三个队列中的第3个元素开始的10个元素移动到第五个队列的第3个元素和第4个元素之间。它所需要的多重队列操作的内容见表1。

表1 多重队列操作示例

2 组件的基本结构

2.1 基本的组件类

组件类 (MQComponent):在.NET架构下,组件被定义为一个Usercontrol类的派生类对象,它负责提供组件的外部接口,由一组预先定义好的一组属性、操作和事件组成。

组件的用户界面类 (GrahicsUserInterface):组件的应用程序界面,用于实现多重双向队列的可视化表示,整个界面由3个可视的Panel对象元素组成,分别用于实现每个队列、每个队列的队列元素以及队列元素的顺序的可视化表示。

图1 给出了组件的用户界面的结构,其中Queue panel用于显示多重队列 (即车辆场地)的结构,Queue Element Panel负责显示队列元素,即车辆。其具体实例可参见图。

图1 组件的界面结构

多重队列类 (MultiQueue):作为用户多重双向队列类的基类,定义了用户多重双向队列类的接口,是本组件的核心类。在结构中作为组件对象的一个组成对象,表示组件中最高层次的队列元素集合。

双向队列类 (Bidirectional Queue):作为用户双向队列类的基类,定义了用户双向队列类的接口,是多重双向队列对象的组成对象,表示一个用户队列元素的集合。

队列元素类 (QueueElement):作为用户队列元素类的基类,定义了组件所需的队列元素类的接口,是组件中最基本的组成元素对象,也是组件各种操作的最基本的单位元素。

多重队列操作类 (OperationList);由一组队列操作命令组成的列表,用于改变组件中指定队列的指定元素的位置。

2.2 组件类之间的关系

图2 给出了组件中定义的主要类和它们之间的关系,其中Usercontrol类是一个.net组件类,用于定义一个封装相关的现有控件并提供其自身逻辑的新控件提供基类。

图2 组件中各个类之间的关系

MQComponent是Usercontrol类[1]的派生类,用于实现本组件自身的业务逻辑。GraphicsUserInterface类是本组件的用户界面类,用于实现本组件中多重双向队列的可视化和与用户的交互操作。

MultiQueue,Bidirectional Queue和 QueueElement是本组件自定义的3个类,分别表示本组件的多重双向队列类、双向队列类和队列元素类。

MultiQueueCommandList、MultiQueueCommand、PictureOfCommand为命令列表类和命令类和命令图形类,用于管理队列操作命令列表,定义了组件的主要操作。

最后的两个类 MoveCommandList、MoveCommand是组件提供给用户的操作列表类。也是组件的一个外部接口。

2.3 组件的外部接口

为了扩展组件的适用范围,本组件以基类的形式对外提供了一组外部接口。用户可通过继承和覆盖的方式使用这些接口使其业务逻辑与组件提供的服务进行有效的结合。

本组件提供的接口包括如下3种:

(1)接口是组件在运行时与终端用户 (操作员)交互所需的操作员接口。这个接口由一组图形化交互操作组成,包括查看和修改队列元素的属性、删除队列元素、选择队列元素、改变队列元素位置等操作。

(2)接口是组件在运行时与客户程序交互所需的动态接口。这个接口主要由组件类定义的一组属性、方法和事件组成。

(3)接口开发客户程序时组件与客户程序员交互所需要的静态接口,这个接口由一组组件对外公开的类组成。开发客户程序时客户可以通过继承的方式使用这个接口。

客户程序接口:运行时与客户程序交互的动态接口主要通过在组件类 (MQComponent)中定义的一组属性、方法和事件来实现。其基本的属性、方法和事件概要叙述如下。

组件主要属性包括:队列元素的显示宽度、高度、字体、字号、颜色、线型、线宽和对齐方式等属性。表示队列元素属性和状态的图像列表等属性。

组件类的方法包括:初始化、添加多重双向队列。

组件的主要方法见表2。

表2 组件的主要方法

组件类的主要事件见表3。

表3 组件的主要事件

程序员接口:设计时与客户程序员交互所需要的静态接口主要由组件提供的若干个基类组成,这些类可以作为用户程序的某些类的基类。

这些类主要包括多重双向队列类 (MultiQueue)、双向队列类 (Bidirectional Queue)、队 列元素 类 (QueueEle-ment)和操作列表类 (OperationList)。这些类的基本定义如下:

多重队列类MultiQueue:在多重队列类MultiQueue的设计中,参照了GOF设计模式中的组合模式,使得组件实例中可以包含多个多重双向队列,使得组件实际上包含了一个多重双向队列集合。

图3 所示的类图中,ID、Name为多重队列的标识符和名称属性;left,top,width和height等为多重队列的显示属性,其值组件的初始化算法自动生成;pQueue为某个双向对列的引用,表示多重队列中的队列集合;属性next是某个多重队列的引用,表示一个组件实例中的多重队列可以是一个复合对象。Draw(Grahpics g)是一个虚方法,用于显示多队列的名称等属性;AddQueue(BiQueue q)方法用于向多重队列中添加一个双向对象;SelectElement(Crectangle rect)和UnSelectElement()方法用于实现交互式地选择队列元素。

双向队列类BiQueue:双向队列类则相对简单,主要封装了双向类的基本操作,包括入队、出队、显示、选择等操作。客户程序可以以继承这个类的方式使用该组件。其基本定义如下:

图3 多重队列类类图

图4 所示的类图中,ID、Name为队列的标识符和名称属性;left,top,width和height等为队列的显示属性;Next是某个双向队列的引用,用于链接多重队列中的双向队列。Biqueue(string ID,string Name)为双向队列类的构造函数;Draw(Grahpics g)用于显示队列的名称等属性;EnterQueue(QueueElement e,int direction)和DeleteQueue(int direction)方法用于添加和删除队列元素;Select(CRectangle rect)和UnSelect()方法用于交互式地选择队列元素;CalculateLayout()用于计算队列元素的显示位置。

图4 双向队列类类图

队列元素类QueueElement:队列元素为一个抽象类,用于表示具体业务逻辑所需要的实体类。客户程序必须继承这个类。具体设计如图5所示。图中,属性ID、Name为队列元素的标识符和名称;IsSelected和IsModified为两个标志,用于标记队列元素的被选中和被修改等状态。该类的方法中,Select和UnSelect用于选择队列元素,IsSelected()和IsModified()用于返回该队列元素的选择状态和修改状态;Draw(Graphics g)、Modify()和Display()等方法均设计为虚函数,用户可以在派生类中覆盖它们。Draw(Graphics g)方法用于显示队列元素的名称和ID,Modify()和Display()方法是两个纯虚函数,这两个函数允许用户在派生类中实现它们,以便用户以自己的方式显示和修改队列元素的属性。

图5 队列元素类类图

队列操作命令列表类 (MoveCommandlist):队列操作命令列表类封装了一组队列操作命令,用于通知用户多重双向队列内部元素位置变化所需要的操作命令细节,实际应用中这个操作列表可能会被传递到现场或某中自动化设备,完成对队列元素实体的实际操作,改变实体元素的位置。组件内部也用于更新组件中指定元素的当前位置。

队列操作命令数据结构见表4。

命令列表类可以用一个简单的由上述队列操作命令数据结构组成的线性表来实现。特别要注意的是生成过程中要校验每一条命令的正确性和整个命令列表的正确性问题。

表4 队列操作命令数据结构

3 组件的实现

3.1 多重双向队列组件的初始化

这个算法根据导入到多重双向队列中的双向队列的个数和层次结构以及队列容量计算每个队列的大小和位置。为队列的可视化过程做准备。

此算法由组件中的 MultiQueueComponent、MultiQueue和BiQueue这3种类型的对象协同实现。3种对象间的协作关系如图6所示。

图6 多重双向队列组件的初始化过程

多重双向队列组件初始化的算法由分布在各个类中的多个操作实现。初始化算法的实现由组件类MultiQueue-Component、多重双向队列类 MultiQueue和双向队列类BiQueue的同名操作CalculateLaout协作完成。具体实现如下。

算法一:多重双向队列组件的初始化

void MultiQueueComponent::CalculateLaout()

1计算并设置每个界面元素的显示位置

2计算组件界面的显示位置。

MultiQueue*p=mMultiQueue;

int left=0;

//设置组件中每一个多重双向队列的显示位置

for(p=mMultiQueue;p!=null;p=p->next;)

left=p->CalculateLaout(left);

Width=left;

Height=EHeight * (LengthOfQueue+2);

int MultiQueue::CalculateLaout(int left)

BidirectionalQueue*p;

int w=0;Left=left;Top=0;//多重双向队列的

for(p=mBDQueue;p!=null;p=p.next)

//设置多重双向队列中每一个双向队列的显示位置

left=p->CalculateLaout(left);

w=w+EWidth;

Width=w;Height=mComponent.EHeight;

return left;//返回下个多重双向队列的左边界

int BiQueue::CalculateLaout(int left)

//设置队列标题的显示位置

Top=0;Left=left;Width=EWidth;Height=EHeight;

for(int i=0,top=0;i<LengthOfQueue;i++)

//设置每个队列元素的显示位置

Rect [i]=new Rectangle(left,top,EWidth,EHeight);

top=top+EHeight;

return left+Width;//返回下个队列的左边界

其它算法的实现与此算法类似,不再给出细节。

3.2 多重双向队列组件的可视化

多重双向队列的可视化过程负责根据初始化的计算结果实现组件中各个可视元素包括多重双向队列、每个双向队列和队列中每个队列元素的可视化。可视化过程如图7所示。

图7 多重双向队列组件的可视化过程

多重双向队列组件的可视化结果可参见图7,图中第一行显示实例中每个多重双向队列,第二行则列出了每个多重双向队列的子队列。组件中每一列表示一个双向队列,每个队列中的每个单元格表示一个队列元素,空白的单元格表示该位置空。

3.3 队列操作命令的可视化生成

组件中,队列操作命令列表的使用过程被分成3个步骤进行:首先,是队列操作命令列表的编制过程。其次,输出生成的队列操作命令列表。在组件外部根据生成的队列操作命令列表完成队列元素对应实体的位置的改变。最后,组件再依据实体的实际位置改变组件内部队列元素的位置。

本组件提供了两种队列操作命令列表的生成方法。一种是使用对话框由用户人工编制的生成方法。另一种是基于图形的交互式生成方法。这两种方法各有优缺点,可以供用户选择使用。但后一种方法是一种自然的工作方法,更符合用户的日常工作习惯。它们使用户可以应用组件提供的功能生成用户所需要的队列操作命令列表,从而帮助用户完成用户所需要的队列元素重排任务。由于篇幅限制,下面仅给出基于图形的生成方法。

(1)队列操作命令的可视化:组件中,为了表达用户对队列元素的操作意图,组件定义了一个规则的图形,来表示一个对指定的队列元素要进行的队列操作。这样,一个完整的队列操作命令列表就可以用一组这样的队列操作图形来直观地加以描述。而按照进出队列的位置不同,组件定义了4种形状不同的图形表示。

一个队列操作图形一个矩形和一个由六条直线段和两条Bezier曲线封闭而成的一个路径组成。矩形区域标识了被选定的队列元素,路径的控制点由组件使用橡皮筋技术在与用户的交互过程中动态生成,路径中贝塞尔曲线两端的一阶曲率则直观地标记了队列操作的方向,箭头端点指定了元素要移入的队列。根据双向队列的定义,容易知道一个队列操作图形可能有4种不同的基本形状。

具体图例如图8所示。图中每个图例的含义是非常直观的。如图8中的图例1表示按向上方向取出4个元素按向下方向放入箭头指向的队列。图例3表示按向下方向取出4个元素按向下方向放入箭头指向的队列。

图8 队列操作命令的图形表示

另外,一个队列操作命令图形也可以包含多组不同的队列元素。如图9所示。

图9 队列操作命令图图示

组件中,队列操作命令图形由PictureOfCommand类实现,它与其它类的关系见图2。

(2)多重队列操作的交互式生成:这样,任何一个对队列元素位置改变的意图 (队列操作命令)就可以由一组既定的队列元素操作图形来加以描述,所以这就使得用户可以通过创建一组这样的队列元素图形来实现其要对队列元素位置的修改。组件内部还实现了根据一组图示生成和导出与之等价的队列操作命令列表的功能,该功能以激活一个特定事件的方式将这个操作列表传递给客户程序。

图9 给出了一个完整的队列操作命令图形。图10给出了图9中队列操作命令的执行结果。表5给出了图9中队列操作命令导出的对列操作列表。

另外,根据这个队列操作命令列表修改相应队列元素位置的算法显然是很容易实现的。

图10 队列操作命令的执行结果

表5 生成的调车作业计划

4 组件的应用实例

在实际的铁路运输系统开发项目中,应用本组件成功的构建了一个车辆分布和车辆调度操作的分布式可视化操作平台,并以这个平台为基础实现了几乎所有车辆调度作业的可视化操作,同时以此平台为基础构建了该项目的整体架构,实现了车辆调度和管理的数字化[4]。

图11 基于组件的铁路运输系统的体系结构

图11 给出了基于组件的铁路运输系统的体系结构,该体系结构运用了本文描述的软件组件,图中的 “车辆分布组件”就是本文描述的车辆分布组件的一个应用实例。

这个组件与结构中其它各组件相互协作构了一个完整的分布式铁路运输管理系统。

图12 给出了铁路运输管理系统项目中的一个组件应用实例,它表示了某作业区某一时刻的车辆分布情况。

在该应用中,每一个组件实例被映射为某一个作业区,一个多重双向队列被映射为一个车场,一个双向队列被映射为一条股道,而一个队列元素则被映射为一个车辆。而一个组件实例上的一个队列操作命令列表实例则被映射为一个作业区上一次车辆调度作业的调车作业计划。系统中所有组件实例构成了整个系统的一个完整的车辆分布的可视化分布和调度平台。项目中该组件的各个实例与项目中其它类型的组件相互配合则构成了整个铁路系统中完整的车辆分布模型,从而实现了整个系统中车辆的实时的和精确的管理。

图12 车辆分布组件应用实例

5 结束语

由于篇幅关系,本文仅概括性地给出本组件的主要设计思路和实现方法而忽略了很多技术细节。

本文所述的方法是从实际案例中提炼总结出来的,在实际项目中,这个方法有效地解决了项目中面临的诸如软件通用性等多方面的技术难题,提高了项目的开发效率和质量,同时也极大地降低了软件开发的成本。希望本文方法能够给对本文感兴趣的读者以一定的启发和帮助。

本文提出的软件组件的另一个主要问题是该组件的适用领域问题。表面上看起来,本文提出的软件组件似乎仅适用于车辆分布和车辆调度。但本文方法仍然可以应用到那些场地相关性较强的大型仓储管理领域或物流领域[10,11],如集装箱货场装卸管理、智能存车场管理等多个应用领域。随着社会的发展和科技的不断进步,本文提出的组件和设计思想仍然会有较大的适用空间。

[1]Juval Lowy..NET component programming [M].USA:O’Reilly Media Inc,2005.

[2]CHEN Honglong,LI Renfa,LI Rui.A high dependable com-ponent assignment method in selfadaptive software based on architecture[J].Journal of Chinese Computer System,2012,33 (6):1153-1158 (in Chinese).[陈洪龙,李仁发,李蕊.一种面向体系结构自适应软件中的高可靠性组件分派方法[J].小型微型计算机系统,2012,33 (6):1153-1158.]

[3]YAN Song.Study on loosely-coupled component communication paradigm [J].Computer Engineering and Design,2012,33 (3):991-997 (in Chinese).[严勇.松耦合组件的通信模式研究 [J].计算机工程与设计,2012,33 (3):991-997.]

[4]GE Xinmao,SHEN Changxiang.Method for layering components towards structured protection [J].Computer Engineering and Application,2011,47 (36):25-28 (in Chinese).[盖新貌,沈昌祥.一种面向结构化保护的组件层次划分方法[J].计算机工程与应用,2011,47 (36):25-28.]

[5]ZHANG Li.Application of paging component based on modelview-controller pattern [J].Computer Application,2011,37(21):255-257 (in Chinese).[张俐.基于 MVC模式的分页组件应用 [J].计算机工程,2011,37 (21):255-257.]

[6]GAO Siwei,ZHANG Dianye.A study on improving adaptability of shunting system model[J].Journal of Transportation Systems Engineering and Information Technology,2003,3(1):84-88 (in Chinese).[高四维,张殿业.提高调车作业指挥模型系统适应性的研究 [J].交通运输系统工程与信息,2003,3 (1):84-88.]

[7]WANG Yalin,ZHOU Ying.Shunting trip plan assistant making system based on MVC [J].Computer Engineering,2010,36 (21):257-259(in Chinese).[王雅琳,周颖.基于MVC的调车作业计划辅助编制系统 [J].计算机工程,2010,36 (21):257-259.]

[8]SUN Xuebo,WANG Zhu.A general software design approach based on layered meta data [J].Computer Application and Software,2008,25 (11):112-114 (in Chinese).[孙学波,王姝.基于元数据的通用软件设计方法 [J].计算机应用与软件,2008,25 (11):112-114.]

[9]WANG Siming,MA Zili,CHEN Yongyi.A model of multiple queues system with double cyclic mobile service[J].Journal of Lanzhou University (Natural Science),1991,27 (4):10-18 (in Chinese).[王思明,马自立,陈永义.多队列双向循环移动服务系统的研究 [J].兰州大学学报 (自然科学版),1991,27 (4):10-18.]

[10]ZHENG Rong,DONG Shaohua.Inventory information visual management system in plane warehouse [J].Logistics Technology,2006 (3):194-196 (in Chinese).[郑荣,董绍华.平面仓库库存信息可视化管理系统的研究 [J].物流技术,2006 (3):194-196.]

[11]CAO Langcai,LUO Jian.Visualization system design and storage location optimization of AS/RS [J].Journal of Xiamen University,2012,51 (1):48-50 (in Chinese).[曹浪财,罗键.可视化自动仓储系统设计与货位优化 [J].厦门大学学报 (自然科学版),2012,51 (1):48-50.]

猜你喜欢
列表队列双向
双向度的成长与自我实现
降低寄递成本需双向发力
用“双向宫排除法”解四宫数独
学习运用列表法
扩列吧
队列里的小秘密
基于多队列切换的SDN拥塞控制*
在队列里
丰田加速驶入自动驾驶队列
一种软开关的交错并联Buck/Boost双向DC/DC变换器