一般来说,当某一个对象有多个集合类型的子元素时,我们都会给每个子元素创建一个集合对象来承载子元素,类似于:
public class Process
{
public var isExecutable:Boolean;
public var refLaneSet:LaneSet;
public var startEventList:ArrayList;
public var endEventList:ArrayList;
public var taskList:ArrayList;
public var serviceTaskList:ArrayList;
public var sendTaskList:ArrayList;
public var receiveTaskList:ArrayList;
public var userTaskList:ArrayList;
}
一般来说,这是没什么问题的。但是某些情况下,例如在图形化与结构化文档之间进行转化时,这样做有很多弊端。如图:
图中:
Participant1,展现类型为PoolDiagram,对应模型为之前的Process对象;
Task1,展现类型为UserTaskDiagram,对应模型为UserTask;
Task2,展现类型为ManualTaskDiagram,对应模型为ManualTask
我们每向Participant1中增加一个UserTaskDiagram或者ManualTaskDiagram时,都需要向对应的Process中增加UserTask或者ManualTask对象;删除时也是如此。这时候就需要通过判断图形的类型来向相关的模型列表中增加模型对象,删除也需要判断。在类型比较少的时候,这样做比较简单,但是如果类型比较多的时候,特别是类型数量是一个变化点的时候,这种处理方式局限性就很大了,每次变动,都会对既有的代码造成影响。具体的代码可能类似于:
增加:
If(diagram is UserTaskDiagram) Process.UserTaskList.add(userTask)
Else if(diagram is ManualTaskDiagram)Process.ManualTaskDiagram.add(manualTask)
......
......
删除:
If(diagram is UserTaskDiagram) Process.UserTaskList.remove(userTask)
Else if(diagram is ManualTaskDiagram)Process.ManualTaskDiagram.remove(manualTask)
......
......
即使我们将这段代码封装到一个地方,这个地方在新类型增加时也需要改变,有没有一种方法可以在类型增加时不改变既有代码呢?答案是肯定的。
具体方案如下:
public class ContainerElement
{
private var _typeListDic:Dictionary=new Dictionary();
public function addChildElement(element:BPMNElement):void
{
if(!_typeListDic[element.type])
_typeListDic[element.type]=new ArrayCollection();
_typeListDic[element.type].addItem(element);
}
public function removeChildElement(element:BPMNElement):void
{
if(_typeListDic[element.type])
{
var index:int=_typeListDic[element.type].getItemIndex(element);
if(index!=-1)
{
_typeListDic[element.type].removeItemAt(index);
}
}
}
public function getChildElements(classInfo:Class):ArrayCollection
{
if(!_typeListDic[classInfo])
_typeListDic[classInfo]=new ArrayCollection();
return _typeListDic[classInfo];
}
}
public class Process extends ContainerElement
{
public var isExecutable:Boolean;
public var laneSet:LaneSet;
public function Process(){}
public function get type():Class
{
return Process;
}
}
上面的代码将所有的类型列表相关的操作封装在ContainerElement中,该类维护一个类型和对象集合的映射关系,从而将相关的判断逻辑从代码中去除。再增加或者去除新类型时我们的process类是保持不变的,相关的增加删除逻辑也会保存相对固定。
经过以上实现,之前的增加删除逻辑变为:
Process.addChildElement(userTask);
Process.removeChildElement(manualTask);