说说TTCN3语言的component实现
以前实现TTCN3执行器的时候,老实说对标准的理解是很不透彻的,最明显的一个例子就是关于组件的使用方面。
组件在TTCN3语言中是一个很重要的概念,除了runson的用例和方法外,由于端口也常常作为组件的成员属性,所以使用上是非常非常广泛的。
简单来说,组件的操作包括create、start、stop、running,新标准还包括alive、kill等。
同时,组件支持比较和复制实现,这对一个复杂类型来说,是一个难点。
type component MTC
{
}
testcase TC() runs on MTC system MTC
{
var MTC Comp1;
Comp1 := MTC.create;
}
OK,我们把MTC实现成一个类是没有问题的,最大的问题是对于create操作如何处理。
我们之前的失败之处在于,Comp1作为MTC的一个实例来做的,而create操作映射于Comp1内的一个标准位来识别。
这样简单的做法非常直观,看似能解决问题,但其实不然。
按照TTCN3标准,组件是可以copy传递的,但这对于我们直接实例化做法来说,不现实。
由于组件是一个很复杂的类定义,使用深copy是费力不讨好的,除非浅copy。
有时候你说了一个谎言,后面要继续说更多的谎言来掩饰。
我们的问题同样,一开始的做法就不是正统做法,后面只会越做越复杂和麻烦。
为了解决浅copy的问题,我们提出一个static id的做法来标识,只copy组件内的create等标志位实现。显然,现在组件间比较,也可以使用这个id来实现,确实是轻量级的方法。
这个做法让我们解决了若干难题,但还是那句,不是根本解决方法。
后来,我们终于面对了一些按照目前做法不可能解决的难题。
testcase TC() runs on MTC system MTC
{
var MTC Comp1;
Comp1 := MTC.create;
var MTC Comp2 := Comp1;
}
按照组件copy语义,Comp2在定义时候通过赋值获取到Comp1的若干标志位信息,这是没有问题的。但如果后面Comp1继续做其他操作,导致标准位改变了,那Comp2如何?
没错,Comp2没有方法映射了,Comp1和Comp2倚靠id和flag方式来实现是不能解决这个问题的,比较内存是两份,不是一份。
OK,上面已经一针见血的指出来了,根本解决问题的方法是你需要单份内存。
这份内存什么时候new出来呢?标准已经说明白了,应该是在create的时候初始化出来的。
现在,我们尝试使用动态类型来实现组件的变量引用.
我们需要一个wrapper实现来描述组件变量,
如CComponentWrapper,这其实是一个代理类,包含一个真正组件的指针。
改组件指针在create操作时候初始化,所以组件操作,我们可以简单使用封装在CcomponentWrapper内实现一下。
这样,判断和复制问题,是轻轻松松就能决绝的事情,
因为CcomponentWrapper是一个很轻量级的代理类,浅拷贝组件指针能很好的实现单份内存,只要经过create操作实例化后,无论复制多少次,内存都是单份的。
最后,为什么我们不使用模板形式实现,如CcomponentWrapper<T>?
这里面有一个前提,就是组件内的所以成员属性,都保存在组件基类内,那组件就不需要显式额外保存这个T信息了,而我们确实是这样做的。