Natural language is extensible; in other words, new notions can be introduced on top of the syntax and vocabulary established so far without the need to learn a new language. Modeling languages also support extensions to their vocabulary so that modelers can express domain-specific notions, rather than be restricted by the more basic and abstract vocabulary of the UML. On the other hand, other modelers find the vast number of concepts offered by the UML to be over the top, so they'd like to be able to confine the use of the UML to ensure that only concepts required in their environment are used. You can extend or confine the UML whichever you need by creating a UML profile, which is a mechanism for adapting an existing metamodel with constructs that are specific to a particular domain, platform, or methodology. Starting with UML 2.0, profiles are now part of UML models, as opposed to being external metadata as they were in UML 1.x. A profile is constructed using any combination of the two mechanisms described in the following subsections. StereotypesA stereotype extends the basic vocabulary of the UML. Stereotypes can be attached to a model element to signify that the element is in some way different from others. For example, we've described some elements of the Bank model as persistent, but this fact is not inherent in the bank (try using the word next time you talk to a teller!), nor is it a part of the UML. By assigning a stereotype «persistent» to a model element of, say, type Class, you state that the class is not just a simple class but a persistent one. Defining a stereotype is similar to creating a subclass of an existing UML type. Figure 7-2 shows an example where the stereotype persistent is defined to be applicable to model elements of type Class. The «stereotype» on persistent indicates the definition of a stereotype that extends (as shown by the arrow) the metaclass Class that is, the class Class in the UML metamodel. Figure 7-2. Stereotype persistent applied to elements of type ClassWith this definition in place, the stereotype «persistent» can only be assigned to model elements of class Class or any of its specializations. If instead you wished to create a stereotype that applies to interfaces as well as classes, you would extend the base class of both Class and Interface, which is Classifier. The definition of a stereotype may include attributes that act as tags.[1] For example, we may decide to store some persistent data in a database and other persistent data in a backup file somewhere. To do this, we can add an attribute to the «persistent» stereotype, say, location, which is an enumeration comprising two literals, db and backup, as shown in Figure 7-3.
Figure 7-3. Defining an attribute for a stereotypeApplying a stereotype creates an instance of that stereotype and links it to the given model element. The stereotype's attributes and associations can then be manipulated just like those of a regular class. The top of Figure 7-4 shows how the UML graphical notation displays the attributes of a stereotype. The bottom of the figure shows the same information as an object diagram of the corresponding UML model elements. Figure 7-4. Showing values of stereotypes and corresponding instance (object) specificationsConstraintsThe UML specification defines the abstract syntax of the set of diagrams that comprise it, but as we mentioned before, it doesn't state exactly how these diagrams fit together nor how to fit them together to form a consistent whole. This problem worsens once you've added your own stereotype definitions. The UML allows a language designer to specify formally which elements to make available, though, and how those elements fit together. The mechanism for this is the text-based Object Constraint Language (OCL). (See the sidebar Object Constraint Language (OCL).) Executable UML, for example, is a subset of UML that uses a simple version of the state machine diagram in which no hierarchical states are allowed. This rule can be stated using OCL by saying that the size of allInstances() of the metaclass Superstate is zero, which neatly makes it "illegal" ever to use a hierarchical state machine. (The function allInstances() is an OCL-supplied function that refers to all of the existing run-time instances of a class.) This is an example of a well-formedness rule, which is a rule that specifies a condition that a model must satisfy in order to be "well-formed." We can also use OCL to define how model elements fit together. In Executable UML, for example, a state machine diagram illustrates the behavior of objects of a class and nothing else. A constraint would assert that the names of the state machine diagrams match only those of classes; in other words, the state machine diagram for "Dog" is legal only if there exists a class named "Dog." (In fact, the rules are a bit more complicated than that, but we'll start with this.) A state machine diagram can also describe the behavior of the set of objects of a class. (And then there are generalization hierarchies and subtype migration, but you get the idea.) These informal rules can be expressed formally in OCL as well-formedness rules, with the result being a set of constraints over a model. Constraints also come in handy when you've defined several stereotypes that are related to each other in some way. Say, for example, you've defined one stereotype called «Session», applicable to classes, and another one called «Entity» that's applicable only to those classes that are not stereotyped «Entity». If not otherwise constrained, the UML specification would allow you to assign both stereotypes to a single class at the same time.
Therefore, you should add an OCL constraint that allows, at most, one of these two stereotypes to be applied to a single class at any time. The combination of the UML metamodel, a set of stereotypes you define, and a set of constraints over instances in that metamodel those instances that capture a developer's model defines a language in the UML language family, the language you wish to use for whatever nefarious purpose you have in mind. |