有些情形需要一个组件能够提供某种接口给多个使用者(这里也将这些使用者称为用户)。比如,为了同时支持多种网络协议的发送和接收功能,TinyOS下的主动消息(AM)通信组件需要提供接口Send和接口Receive给多个客户。再如,提供一项重要功能—计时。TinyOS下每个硬件平台通常都有计时器组件HilTimerMilliC,在平台硬件计时器上实现多个逻辑计时器(软计时器)。应用中有多少个软计时器,就需要HilTimerMilliC提供多少个接口Timer的实例。那么,如何在组件中提供同类型接口的多个实例呢?
第一种方式是在通用模块(在第六章中会介绍通用模块)中提供该接口,再将该通用模块实例化多次,从而达到支持同一类型接口的多个实例。这种做法存在两个缺点:一是浪费代码空间;二是在大多数情况下,这多个实例的实现代码做不到相互独立,相反的,会形成某种协作(依赖性)。例如,在计时器组件HilTimerMilliC上支持的多个逻辑计时器的实现中需要依据共同的策略(比如最早时间到达)。
第二种方式是在组件规范中直接声明多个接口实例,比如,在组件HilTimerMilliC的规范中提供100个类型为接口Timer的实例,如例3.24。
例3.23:(www.xing528.com)
这种方式能够工作,但是每个实例接口中的函数都要有相应的实现。比如,上述组件HilTimerMilliC(实际是HilTimerMilliC封装的某个模块)的实现代码中,要实现100个Timer<TMilli>接口中的各个函数,而这些函数实现几乎完全一样。这种方式不仅比较麻烦,而且产生了大量重复代码。
第三种方式是使用一个参数用来指定在用哪个接口,这类似于POSIX文件系统的文件描述符。在这种方式下,应该生成唯一的计时器标识符,并在调用接口时传递该标识符。这种方式也可以工作,而且不会像第二种方式那样生成多个实现。但这种方式是在运行时传递参数,而通常来说这是不必要的。因为组件通常分配一定数目的计时器,而且仅使用这些计时器。或者说,通常在编译时就可以知道组件使用的计时器集合以及集合的大小,因而没有必要让调用者在运行时传递这个参数,继而引入可能的Bug。
从编程者角度来看,重要的问题不在于使用者调用了哪些组件,而在于需要明确调用从那些组件而来。例如,对于计时器而言,重要的问题是如何区分调用者,以便向正确的组件通知fired()事件。上面介绍的第三种方式基于标识符可以实现区分,但是需要在模块中管理标识符。因为标识符是一个运行时参数,计时器服务组件中通知Timer.fired()事件时,扇出的各调用函数中必须检查这个标识符参数。基于这些考虑,为了支持抽象提供一组同类型的接口实例,nesC提供了参数化接口。参数化接口实质是接口数组,数组的索引是接口参数,标识了调用组件。对于多个接口实例仅需一个实现,接口参数是常量,在编译时确定,避免了运行时传递参数的弊端,既简化了代码,也提高了函数调用的效率。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。