Data Structures and Objects CSIS 2617


Using UML to Document Classes

In order for your classes to be reusable, several issues should be addressed in your documentation. Some information about your class pertains to how your class works internally or how it was implemented. This should not be a part of your documenta- tion. Documentation should be restricted to the information needed to efficiently use the class. This information includes but is not restricted to:

Descriptions of the classes are needed for the user to have a general overview of what the class is or what the class is supposed to model. How the class is described, how much detail to include, or how technical the description should be will depend on the class and the background of the presumed user of the class.

Good documentation should include a detailed description of the class interface. This will include how to use each public data member and member function. These details should include more than a one-line description of what each member func7 tion does. All the parameters should be described including where the parameters come from, where are the values assigned, and so on. An example of how the member function can be used is always helpful to the user.

The class hierarchy (what classes are inherited or contained in the class) is also very important. Knowing the relationship between classes will help the user in con- structing new or derived classes. Besides showing the relationship between these classes, the class hierarchy tells the user what other methods are available to the class by inheritance or containment.

It is important for the user of the classes to understand the behavior of the classes in various scenarios or use cases. The user should be able to understand the classes for more than one view.

What is UML?

The UML (Unified Modeling Language) is a graphical notation used to design, visual- ize, and document the components of a software system and is the de facto standard for communicating and documenting object-oriented applications. The modeling lan- guage has symbols and notations that represent ideas such as classes, the relation- ship between classes, the types of classes, the state the class is in, and the actions the class performs.

When designing your application, we recommend using the modeling language to help you determine what classes are needed and how the classes will be related. It can help you to construct new classes from already existing ones. Use the UML as a tool to help you communicate your object-oriented designs to other programmers. UML has notation to represent the activities and events or the workfiow of a class performed in parallel. Once the system is coded, use the UML to document classes for reuse in other systems. In the future, other software developers may use them.

The UML brings together the approaches of Grady Booch, James Rumbaugh, and Ivar Jacobson's object-oriented analysis and design methods developed in the 1980s and 1990s. It was adopted by the Object Management Group (OMG), an inter- national organization consisting of software developers and information system vendors with over 800 members. The goal of the organization is to push the prac- tice and theory of object-oriented technology in the development of software. The adoption and conformance to the UML gives software developers a consistent lan- guage and tool for object analysis and documentation.

What is a class?

A class is a set of attributes and behaviors that defines a person, place, thing, or idea. When a class is defined, it places objects or concepts that share a set of common characteristics into a group. These characteristics serve to distinguish

one class from another class. There is a difference between the class and an object. A class defines the set of common characteristics. An object is a particular instance of the class or a member of the group. For example, shape can be a class and triangle would be an instance of the class shape.

Classes are used to model real-world objects or abstract data types. If the class represents an abstract data type, then it will perform operations or services on a type of data. If the class represents a real-world object, then the class will model its behavior. Both types of classes will have data.

When designing a class, it is important to keep in mind what you are attempting to model or represent. If the class is an abstract data type then the type of data will determine the operations and services the class will perform. The operations, services, and the data component are what creates the unit called class. Suppose, for example, a generic binary number class: the binary number class will have a data component. The data component will represent a sequence or Os and Is. That data component will be encapsulated so that only the authorized methods can access it. The binary number class will offer a number of operations and ser- vices that can work on its data component. The services and operations defined by the class are determined by the types of operations that can be performed on a binary number. Binary numbers can be:


A binary number can have a mask applied to it. It can be changed to ones or twos complement. We may need the most or least significant bit of the number. These would be the services and operations defined by the binary class. The class would have the binary number and a mask, which would be the attributes. If you wanted to model a real-world object like an automobile, you would have to consider what a car does, the parts of a car, and the features of a car.

The Class Diagram

The class diagram is used to describe the types of objects in your application and the different kinds of relationships that exist among those objects. The class dia- gram can be used to show the attributes and the operations or services that a class provides and the restrictions that apply to the way the objects are connected.

The simplest representation of a class is a rectangular box that contains the class name in the center. The class diagram can also show more details of the structure of the class as well as attributes and operations. The rectangle is drawn with three horizontal compartments. The top compartment contains the name of the class. The second compartments list the attributes or attributes of the class. The third compartment contains the operations and/or services supplied by the class. The compaIrtments can be labeled "attributes" and 'operations." Other compartments can be created and added to your diagram. Another type of compartment can be "responsibilities" or "requirements." The labels should be placed near the top of the compartment. The second and/or third compartments do not have to be shown. Figurel8-1 shows the class diagram for a range-exception class.



A class diagram can have as much detail or as little detail as the developer wishes to convey. When the class diagram is incorporated into other diagrams that represent the entire system or how classes are related to other classes, the simplest representation may be all that's necessary. To communicate how a class is used or how its methods are used, more detailed is required.

Ordering the List of Attributes and Methods

The list of attributes and methods can be presented in some type of order. Order in the list helps to identify and navigate the attributes and services of the class. The order could be:


Alphabetical order is better than no order at all but does not help the user unfamiliar with the class. Ordering by access can be very helpful. It communicates to the user what attributes and methods are publicly accessible. Knowing the protected members will assist users who need to extend or specialize the class through inheritance.

There are two methods to show access: by using the access specifier names or by using symbols called visibility markers, which represent access. These markers are prepended to the data member or member function name. The "+' means public, "#" means protected and "-" means private. The absence of an access specifier or of visibility markers does not infer that they are all public, but, rather, that access is not shown.

Attributes and methods can be classified by using stereotype indication. Stereotype indication is a classification name. It groups the elements in the list with a particu- lar property. The property can be functional, "what function do these methods serve in the class?" The property can express the function type The name is embraced in left and right angle brackets (<< ... >>).

Minimal Standard Interface

Determining the categories for the services and operations that your classes pro- vide may be difficult. Although not always necessary, your classes should provide a minimal standard interface or follow the form of a nice class. This means that the class should contain at least the following methods:


A class that contains at least these methods is considered a nice class. These functional categories can be used to classify the methods of your class. It has been argued that all classes will not need all these methods. The services and operations that a class provides should be dictated by what the class is attempting to model or by the behavior of the object. This may include some of these methods and exclude others. The idea of a minimal standard interface is viewed as a guideline, not a rule.

These categories can be used to help organize your list of services and operations. Categories can express the types of methods your class has. Examples of categories are:


Classifications are very useful, particularly when a class offers many services and operations. For example, the string class is huge, categorization help in communicating what services are offered. These categories are used because they are very descriptive of the services and operations of the string class. Categories should be selected to best describe the services offered by a class.

Showing a Parameterized Class

The UML offers notation to represent a parameterized or template class. The parameterized class is created in C++ by using the keyword template:

template <class Type> classname { ...}

The argument Type represents any type passed to the template. Type can be a built-in type or a user-defined type. When the type has been declared, the template becomes bound. The template is said to be bound by the element passed to it as the parameterized type. For example:

template <class T> class vector ( ... )

in C++ this means the vector class is a template class. A vector is a container that can hold any type. A vector can be declared to hold strings and a vector can be declared to hold ints:

vector<string> StringVector;// holds a vector of strings
vector <int> NumberVector; // holds a vector of integers

This can be depicted by using UML. Because the template is a class, it will also be represented as a rectangular box. Attributes and services can be listed as with any other class. In the upper right-hand corner is a smaller dashed rectangular box suggesting the class is a template class. Within the smaller box is a capital T. This T is a placeholder for the parameter type. To represent more than one type use more than one letter.

Template classes are really part of the parameterized programming model and are not really from the object-oriented model. Pure object-oriented languages such as Java, do not include parameterized types. However, it is a powerful programming technique and helps to speed development, so we cover them here.

There are two ways to depict a bound template. One way simply copies C++ syntax into a box. The other way allows you to show how the declared template object is linked to the template and allows you to show the name of your declared object. Figure 18-3 shows the class diagrams for the template class vector unbound and the two alternative ways to show the template bounded to string and int types.


The dashed line from the template object to the template class with the hollow triangle beneath the template class, shows the template object has a dependency relationship with the template class. The template object depends on the template class. The template can also be viewed as a refinement of the template class. Refinement is a general term to indicate a greater level of detail about the class. The stereotype indicator, < < b i n d > > specifies the type of refinement or dependency between the class and the object. Because the object is not derived from the template class, no new services can be added to the bound element. The template class defines all services.

Showing Instantiations of a Class

Figure 18-3 shows the instantiation of a template class. The instantiation of other classes can also be depicted in an object diagram. An object is an instantiation of a class. The object has an identity and gives values to attributes; this can be depicted in the object diagram. The object name is placed in the compartment where the class name is located. The class name can be omitted or the object name can be placed in front of the class name and separated with a colon (:). Instead of listing the attributes and services, the attributes to which the object assigns values are listed in the compartment under the class and object name. If, within the life of the object, attributes change values, then multiple versions of the object can be drawn showing the change in values. Between each version of the object, the stereotype indicator < < b e c o rn e s > > is shown.

An object class also has a simpler representation. An object can simply be depicted as a box containing the name of the object or the name of the object and the class name. The name of the class preceded by a colon means the class is instantiated but the name of the object is not shown.

Showing Relationships with Other Classes

Classes can have many types of relationships between them. Relationships could be depicted as simply some type of connection. But "some type of connection" is not very useful to the user of your class. The more descriptive the relationship, the better the understanding of how the classes can be used. As the number of classes in your class library or application framework grows, class diagrams become a necessity. Table 18-1 lists the class relationships that can be represented by UML.

The UML has notations to show the class relationships: inheritance, containment, dependency, and association. Aggregation and composition are two types of con- tainrnent. Use and bound are two types of associations. Import, refine, trace, and access are the four types of dependency relationships.

A class can inherit another class; this is a familiar class relationship. The inherited class is called the base or parent class and the new class is called the derived or child class. When a class inherits another class, the derived or extended class is everything the base class is and more. The keyword "extends" is a term used to describe the derived class. The derived class adds new functionality to the base class, therefore "extending" what the base class was originally capable of doing.

UML RelationshipsDescription
Inheritance A solid line is drawn from the derived class to the base class with a hollowed-headed arrow pointing to the base class.
Containment:
aggregation
A solid line is drawn from the aggregate class to the class it contains with a hollowed-diamond drawn at the aggregate end og the line.
Containment:
composition
A solid line is drawn from the composite class to the class it contains with a solid-diamond drawn at the composite end og the line and a stick-headed arrow pointing to the composite class.
Dependency A dashed line with a stick-headed arrow is drawn from the client class pointing to the supplier class; the client depends on the supplier.
Association:
use
A solid line is drawn between the classes that have an association.
Association:
bound
A dashed line is drawn from the template object with a hollowed-headed arrow pointing to the template class.

A derived class also "specializes" the base class. A base class describes the general case and the derived class describes a special case. The base class may consist of just a few virtual or pure virtual methods. The usefulness of the class may be based on the specialization created by the derived class. For example, the range_exception class specializes the domain_error class. Listing 18-1 lists the class declarations of both classes.

The domain_error class contains one method, what(). what() method is used to return a string that describes the type of error that has occurred. The range_exception class specializes the domain_error class by adding two methods: validDomain (string X) and string validDomain(void). These methods set and return domain information. They also return the type of error that has occurred along with a valid, safe domain.

The methods lowerlimit(void) and upperLimit(void) will return the lower and upper limit of a function for which the range_exception is being used.

A class can have another class as a data member. This relationship is called containment. A class is "contained" in another class. The range_exception class contains a string DomainExplanation.


// Listing 18-1
// The class declarations for domain-error and range-exception
// classes

class domain-error : public logic_error{
public:
   domain_error(const string& what_arg): logic_error
               {what_arg} { }
};

class range_exception : public domain_error{
protected:
   string DomainExplanation;
   int LowerLimit;
   int UpperLimit;
public:
   range_exception (void) : domain_error(DomainExplanation) { }
   range_exception(const string &X) : domain-error(X) { }
   range-exception(const range-exception &X);
   range-exception&operator=(const range exception &X);
   void lowerlimit(int X);
   int lowerLimit(void);
   void upperlimit(int X);
   int upperLimit(void);
   string validDomain(void);
   void validDomain(string X);
};

The containment relationship can be described further as "the type of containment" A containment relationship can be further described as aggregation or composition. An aggregate is formed by a collection of particulars into a mass or a unit. For example, a bitmap can be considered an aggregation of pixels as a,crowd is an aggregation of individual people. Therefore, an aggregate class is a class that contains a collection of particulars or things that form the class. Composition is another type of containment. A composite is made up of distinct parts. For example, a computer is a composite of many parts: CPU, hard drive, mother board, memory, and so on.

Classes can have an association, which exists between instances of classes. Association between objects suggests that there is some type of connection between them that excludes inheritance and containment. The association can be a "use" relationship. For example, an application uses a window (or user interface). The application does not contain or inherit a window. A window does not inherit or contain an application. The application uses the window in order for the user to interact with it. If the application class is constructed correctly, the user interface and the application are separate classes. A user interface can be used by different applications. An application can use different user interfaces.

Another relationship is dependency. The classes that participate in the dependency are the client and the supplier. The client is the class that depends on the other class, the supplier. A dependency exists between two classes if a change in one class (client) causes a change in the other class (supplier). If the supplier is contained in the client class, or the supplier is a parameter of a method in the client class and the interface of the supplier class changes, this may cause messages to become invalid. If the data values in the supplier changes, this may cause changes in the values contained in the client class. Both scenarios demonstrate a dependency between classes.

Showing Inheritance

To depict relationships between classes, the UML uses special line notations for each type of relationship. Some line will have a shape on the end of it called associated end adornments. These adornments can be diamonds, or arrowheads. The arrow-heads can be solid, hollow or stick. For inheritance, a line is drawn from the derived class to the base class. Where the line meets the base class, there is a large hollow arrow-head.

The inheritance diagram can show how a base class is inherited by more than one class. There are two ways to depict this. One method is to have one arrow-head connected to all of the derived types forming a type of tree. This method has a shared target style. The target is the base class and the derived classes jointly target the base class. The other method is to have each derived class have its own line to the base class. This method has a separate target style. Here, each derived class separately targets the base class. Figure 18-5 shows the inheritance diagram for the domain_error, invalid_argument, length_error and out_of_range classes. These classes inherit logic_error class. The figure shows the shared and separate target styles that can be used to depict inheritance by more than one class.


Multiple inheritance can also be represented in the inheritance diagram. Figure 18-6 shows the class diagram of the basic_iostream class. The basic_iostream class inherits basic_istream and basic_ostream. The derived class basic_iostream, has two targets instead of one: basic_istream and basic_ostream classes. The targets are the classes that are inherited by the derived class.

Showing Containment

Containment can be an aggregation or a composition. Each type of containment has its own special way of being represented. Figure 18-7 shows classes representing both types of containment. Aggregation is represented with a line between the object contained in the class and the aggregate class. At the end of the line at the base of the aggregate is a large hollow diamond. Composition is depicted the same way but the diamond is filled. Also there is a stick-headed arrow pointing to the composite class. In Figure 18-7, a bitmap is an aggregate class that contains pixels. The computer is a composite class that contains a CPU, hard drive, and memory.


Showing Other Relationships

Dependency between classes is depicted as a dashed line with a stick-headed arrow. The classes that participate in the dependency are the client and supplier classes. The client class depends on the supplier class. The line is drawn from the client to the supplier with the arrow poiting to the supplier class. A stereotype indication label can be placed next to the path.

Association relationship is represented by a solid line between the classes, with a label describing the type of association. Association can be described further with more UML notation.

Refining the Relationships

UML supplies additional notation to refine or present more detail about the relationship between the classes. Another type of notation is called multiplicity. Multiplicity notation indicates how many objects may participate in the relationship between classes. Table 18-2 gives some examples of multiplicity syntax and its meaning. The multiplicity notation can be applied to one or both classes.


Table 18-2 also shows how sometimes X and Y classes utilize the multiplicity nota- tion, other times just the Y class. For example, consider the bitmap and a computer class mentioned earlier as examples of the containment relationship aggregation and composition, respectively. A single bitmap is an aggregation of pixels. How many objects participate in this relationship? With one bitmap and many pixels there is a one-to-many object participation in this aggregation. This would be case 10 in Table 18-2. A computer and its parts also have a one-to-many object participa- tion in this composition, one computer with many parts.

A human being is also a composite of many parts. But there is definitely a one-to- one relationship with the brain, stomach, heart, and so on. (at least at the time this book was written). This would be case 8 in Table 18-2. On the other hand, a com- puter can have many CPUS, hard drives, motherboards, and so on. We can think of countless examples. As you can see, there can be a one-to-one, one-to-many, many- to-one, or many-to-many object participation in a given relationship.

The number of objects in a relationship may have a lower and/or upper limit. In other words, there may be a minimum and/or a maximum number of objects needed in order for the relationship to be valid. A computer must have at least one CPU and memory to be considered a computer. The upper limit on how many processors a computer can have is difficult to calculate. Massively parallel processors (MPP) could have hundreds, even thousands of processors. The Cray T3D and Intel Paragon has from 32 to over 2000 processors. A computer needs at least two regis- ters Oet's say 2 bytes) to be useful. The upper limit on memory would probably be infinite notwithstanding the physical nature of the computer. A computer does not need hard drives, motherboards, and so on to be considered a computer. A human being has to have at least one brain and one heart to be considered human. How many can we have? A bitmap needs at least one pixel and as many pixels as needed to fill the largest display screen.

Multiplicity specifications can be expressed as an interval range of nonnegative integers:


lower limit .. upper limit

This is a closed inclusive interval. The specification also uses an asterisk (*) which means infinite. The asterisk can be used on the upper limit. Therefore,


lower limit .. *

means an interval with unlimited upper bounds. If the multiplicity comprises of just the asterisk it means the range is unlimited nonnegative integers or:


0 ..*

The specification can also be a single integer value. Figure 18-8 shows multiplicity used in the relationship of a computer to its parts. A computer can have from one- to-many CPUS, zero-to-many hard drives, and two-to-many bytes of memory.



Navigability is another notation used to give more detail about the relationships classes. Navigability is represented as a stick-headed arrow-head. It depicts the direction of the relationship between two classes. For example, if the relationship is dependency, the direction of the arrow would show the direction of the dependency. An arrow pointing to the supplier means the client depends on the supplier. This is called a unidirectional association. If the classes depend on each other then' there would be a single line with no arrows. This is called a bidirectional association.