|
Hello Jeroen,
You can certainly implement UML ports in MetaEdit+. Whether you can implement the same behaviour as in a particular UML tool is a different question: tools seem to vary significantly, and not all of their approaches are necessarily well-founded.
At the simpler end of the scale, there are UML tools that are just drawing tools. For that kind of behaviour I'd tend to opt for implementing ports as role symbols: instead of an arrowhead, have a small square and set it not to rotate. That will let you move the ports around freely. It also allows a way of creating diagrams that many seem to use with ports in UML: rather than defining what ports and interfaces an element has, just draw a usage of that port. To make an analogy with functions, that's like writing "float a = sqrt(2)" and taking it as implying the definition of a function "float sqrt(int)". If we're just drawing to sketch and to understand, that's fine, but if we're modeling to generate code or indeed anything precise, we probably need to separate definition from use.
In the roles you can have the port information just as a string, or as an object - possibly itself containing objects for interfaces, which could then be reused in several ports. Alternatively you can have the port definition objects somewhere else in the model, and have the role fetch the text you want to display with a generator.
That leads us to the next stage of "port evolution": Dynamic ports, implemented with MetaEdit+ templates ( http://www.metacase.com/support/50/manuals/mwb/Mw-3_2_9.html" rel="nofollow - Workbench User's Guide 3.2.9 , see also Section 4 in the http://www.metacase.com/download/metaedit/MetaEdit+%205.0%20Beta%20Primer.pdf" rel="nofollow - 5.0 beta primer ). Here ports are defined first as a normal part of the model, often in a subgraph or object collection property of the object that will display them. The template element in the symbol definition tells MetaEdit+ where to find the list of ports, how to lay them out along a path in the symbol, and what little port symbols to show for them.
The dynamic ports are automatically laid out, which saves the modeler time, keeps the models neat, and makes reading models easier - whenever you look at an object with ports, its ports are in the same places. In many ways, an object with dynamic ports is like a subtype or reusable component, and so it's more effective if it looks the same and is connected the same wherever it's used - just like having different symbols for different types, and also like the static ports which you can use when implementing circuit diagrams with things like AND gates. In our analogy with functions, it's like the consistent ordering of function arguments.
The modeler can affect the ordering of the ports in an object by changing their ordering wherever they are actually defined. For example, in languages where ports are used for data flow, often one template is placed on the left of an object, and shows all the In ports, and another template on the right shows the Out ports. The ports may well then be defined in a subgraph specifying the implementation of the object, and the templates can be told to display the little port symbols from top to bottom, in the same vertical order as they are shown in the subgraph:
do subgraphs
{ foreach .In
orderby y NUM
{ id newline }
}
If you want still more freedom to affect the layout, you can tell MetaEdit+ to order the ports based on the position of the relationships attached to them. If a relationship isn't attached, they'll be ordered as by default, but when you attach a relationship, the port will automatically move to make the line from the relationship level. The placement/ordering algorithm to assign In ports to possible 'slots' on the left edge would be something like this:
1. get ports from subgraph 2. allocate ports that have relationships attached - allocate greedily to best available slot based on y coordinate of relationship - store in a variable mapping port's unique oid to slot index 3. allocate unused ports from subgraph into remaining slots in order 4. output list of ports by iterating over ports from subgraph, ordering them by their slot index
/* quick and dirty - all attached and unattached sorted separately */ do ~To { variable do #() { 'y' oid } write do >() { y } close } do subgraphs { foreach .In orderby variable 'y' oid read NUM, y NUM { id newline } }
Finally, if you want total freedom for the layout of your ports - as some tools allow, with the ball on the end of the lollipop being able to be freely placed - make the balls into their own little objects, and the stick be a relationship.
One more thing to think about, though: most DSM languages that have concepts like "Component" and "Port" are still at a low level of abstraction, close to the implementation - like UML. Consider whether you can raise the objects-with-ports to be real types, making the language more concrete and increasing productivity. Maybe there would be one team of people who could create such types, and another team that would build models using them? That's certainly a common and effective pattern we've seen in industrial DSM cases.
|