When code is automatically generated from a model (in the present case, a UML model), there are two approaches:
A design model is derived from an analysis model by adding support classes to map the analysis model to the Software Architecture (see Software Architecture). An example would be a container for all the instances of a given class.
A tool which uses this approach is Rational Rose.
An analysis model contains classes and relationships that are part of the subject matter of the analyzed subsystem. Code which supports the execution of the model (for example, navigation from an instance of one class through an association to find the set of corresponding instances of another class) is automatically generated.
Tools which use this approach include Software through Pictures from Aonix, Rhapsody from I-Logix, xUML from Abstract Solutions (was Kennedy-Carter), BridgePoint from Mentor Graphics (was Project Technology; now open-sourced), and the present project.
Automatically-generated support code comes in several flavours:
The code generation process writes out new code. An example is the creation of a record structure to correspond to instance attributes.
The new code is an instantiation of an existing generic component.
The new code is an extension of an existing (base) component.
This set of Use Cases (well, that’s what I’m calling them!) covers the requirements to be met by the Software Architecture (see Software Architecture), particularly by supporting components.
The Actor concerned is the analyst who specifies the logic of operations or actions. The programmer who implements these specifications (or, in an advanced tool such as iUML or BridgePoint, implements the mechanisms which provide full translation) is, rather, concerned with building components to meet the requirements expressed here, and (eventually) with using them.
No distinction is made at this point between generic and base components.
It isn’t possible to maintain all the invariants of the model (for example, constraints on relationships) within any given operation; on the other hand, the analyst must not allow any operation to complete with the model in an inconsistent state.
The existence of an Instance must be independent of how many copies of its data are held. One possibility is to have the Class be responsible for the existence of Instances.
When an Instance of a Class is to be created, the analyst specifies a set of attributes which cover the Class’ Identifier (see Identifier).
Once the Instance has been created (with default values for non-identifier attributes), other attributes are set.
It would be possible to support any legal combination of attributes (besides the identifying attributes, which must be supplied); this is likely to be prohibitively complex, unless the implementation language allows default values for subprogram parameters. An acceptable alternative strategy would be to require that all the attributes be supplied at once.
The prime way of deleting an Instance is to ask its Class to delete it. This could either be in terms of the complete Identifier (see Identifier) or by using a valid selected Instance.
An Instance can be asked to delete itself; this will resolve into the Class operation discussed above.
There are five (any advance on five?) ways of getting a single Instance:
Once the Instance has been accessed, various operations are possible:
Some operations (see see Access an Instance) result in single Instances; others result in (possibly empty) sets of Instances. These include:
Given a set of Instances (which includes the set of all the Instances), the analyst must be able to specify operations on the set.
In some cases these may be predetermined (for example, determine the number of members of the set).
In other cases the actual operation is analyst-specified. Variations to consider include:
The above list is expressed as though the operation must apply to each set member. Clearly this isn’t necessarily the case; however, it may often be cleaner to perform a more rigorous selection first and then apply the operation to all the members of the result set.
In some simple cases it may be possible to implement an association between instances of two classes (or two instances of the same class) without introducing a “third party”. In most cases, though, a third party class will be necessary.
For example, if it is (or may be) necessary to navigate the association in either direction, language rules may well prohibit the mutual visibility that would be necessary (Ada 95 doesn’t permit this unless the “with type” feature is implemented).
Given two distinct instances (is that true? is it possible for an instance to be associated with itself?), the analyst can require that they be linked via an association. In some cases (eg, unconditional associations), instances must be associated. Ideally some form of model integrity check should be supported. This should include checks that no extant association involving either instance already exists.
Normally it will be obvious which end is which; this won’t be so for reflexive associations. It must be possible to specify which is which: the role names (phrases) may prove useful.
The Software Architecture (see Software Architecture) may support handles, in which case this operation may be expressed in terms of handles; if not, it will have to be in terms of Identifiers.
Deleting an association between two Instances may require that one or both of the Instances be deleted, to maintain model integrity; this is left to the Analyst.
The Software Architecture (see Software Architecture) may support handles, in which case this operation may be expressed in terms of handles; if not, it will have to be in terms of Identifiers.
Following the Shlaer-Mellor rules, all parent classes in inheritance relationships are, in a sense, abstract: whenever an instance of the parent class exists, there exists precisely one related instance of one of the child classes.
Given a new instance each of parent and child classes, the analyst must require that they be linked via an inheritance relationship. Ideally some form of model integrity check should be supported. This should include checks that no extant relationship involving either instance already exists.
The Software Architecture (see Software Architecture) may support handles, in which case this operation may be expressed in terms of handles; if not, it will have to be in terms of Identifiers. Note that the Identifier of the child class is very likely to be identical to that of the parent.
Deleting an inheritance relationship between two Instances requires that both of the Instances be deleted, to maintain model integrity; this is left to the Analyst.
The Software Architecture (see Software Architecture) may support handles, in which case this operation may be expressed in terms of handles; if not, it will have to be in terms of Identifiers.
Migrating an inheritance relationship between two Instances requires that the old child Instance be deleted, to maintain model integrity; this is left to the Analyst.
The Software Architecture (see Software Architecture) may support handles, in which case this operation may be expressed in terms of handles; if not, it will have to be in terms of Identifiers.
Instances of a Class must be uniquely identifiable by some attribute or combination of attributes. For example, a Vehicle Excise Disk might be identified by the combination of Vehicle Index Mark and Validity Start Date. Vehicle Index Mark and Validity Start Date then become “identifying attributes”, whereas Date Of Issue and Period Of Validity are just common-or-garden attributes. A different analyst might make a different choice (Serial Number, for example) governed often by practical considerations such as whether they already exist.
The Software Architecture, as considered here, has several components, but basically it comes down to how the analyst’s model is implemented: