Tags and keywords
CASE1: Signal family as an inheritance hierachy with variations on attributes (left)
AcceptEventAction will catch a sub-Signal type. This can help with reuse of logic across a family of Signals. But some scripting may be needed to determine the received signal type and take corresponding actions. Special handling is required if the sub-signals have additional attributes not defined on the base signal.
In the example shown left and two Signals SubSignalA
and SubSignalB
that extend BaseSignal
, each with different attributes a:Integer
and b:Real
respectively.
A SignalA
with a = 1
is sent via a SendSignalAction then caught via an AcceptEventAction for BaseSignal
, with a Groovy script on an OpaqueAction used to detect the Signal type actually caught. A switch
statement is used to print each Signal type along with its corresponding attribute value.
Instead of just printing, a real implementation might invoke different handler actions for each sub-Signal type.
It's worth checking out the fUML spec to find out what fields the script can access.
Pro: Appropriate attributes offered on Pins of each specific SendSignalAction.
Con: Can lead to hierarchy explosion, and need a specific SendSignalAction for each sub-Signal.
If your Signal family has attributes beware that:
CASE2: Signal family parametrised by a signal kind with covering attributes (right)
Consider instead using a SignalKind enum to parametrise a signal family via a single Signal base (here ParamSignal
). Detecting the kind of Signal actually caught is then trivial, as it's available on an un-marshalled Pin.
Note that this approach works best when the attributes are all the same for each "signal" kind, i.e., the attributes required for each kind are covered by the base Signal that carries the enum.
In the example shown, only the attribute a:Integer
is deemed relevant for signal kind sigA
. A Groovy switch
statement is used to handle each kind and print only those attributes deemed relevant for the signal kind.
Instead of just printing, a real implementation might invoke different handler actions for each signal kind.
Con: Because the single parametrised Signal has to cover every anticipated attribute, every attribute has to be set on the SendSignalAction, even if not relevant for every "signal" kind. Unfortunately, you can't just use a default such as null
on the attributes, it won't be detected on the SendSignalAction Pins. You also can't use a LiteralNull on a Pin that expects a type, such as for b:Real
, which attribute might not be relevant for a parametrised signal of kind sigA
.
Pro: Avoids Signal hierarchy explosion. A single SendSignalAction can be used with Pins for attributes driven according to the signal kind. Typically, the shared SendSignalAction would be within one Activity, and then driven by via a CallBehaviorAction within dedicated Activities for each signal kind as required.
BTW: It's a great shame that ValuePins are not supported in fUML! It would be nice to avoid having to use all of those ValueSpecificationActions!
Of course one can instead just use scripting.