3.1 Classes and Objects

Class diagrams show classes that represent concepts, while object diagrams show objects that represent specific instances of those concepts. The next few sections talk in detail about the representation of classes and objects in class and object diagrams.

3.1.1 Classes

As discussed in Chapter 2, a class is a general concept. For example, the project management system involves various general concepts, including projects, managers, teams, work products, requirements, and systems.

A class defines a type of object and its characteristics, including structural features and behavioral features. Structural features define what objects of the class know, and behavioral features define what objects of the class can do. For example, in Chapter 2 you saw that individuals of the Manager class have names (something they know), and can initiate and terminate projects (things they do). Structural features include attributes and associations. Behavioral features include operations and methods.

The most crucial aspect of a class is that it has semantics: some agreed upon meaning between whomever is communicating about it. For example, when I discuss a project, what does a project mean to my audience? Is it an effort that lasts one week or one year? Is it an effort that requires a manager and other human resources? And so forth. Such meaning is very specific to the audience and domain in which the class is used.

In a UML class diagram, a class is shown as a solid-outline rectangle with three standard compartments separated by horizontal lines. The required top compartment shows the class name, the optional second compartment shows a list of attributes, and the optional third compartment shows a list of operations. The second and third compartments need only show the specific information you want to communicate using a given diagram. You don't need to show all of a class's attributes and operations all the time.

Figure 3-1 shows various fundamental classes associated with the project management system in our case study, including Worker, UnitOfWork, and WorkProduct, using the most basic notation for classes.

Figure 3-1. Classes
figs/Luml_0301.gif

A worker is a person or group of people who perform work, including project managers, resource managers, human resources, and system administrators. A unit of work is a unit of effort, which includes capturing and analyzing requirements, as well as designing, implementing, testing, or deploying a system. A work product is anything produced and used within a project, including the requirements and the system. Notice that a class should be named using a noun phrase. Classes, as you should recall from Chapter 2, represent concepts that you discover by focusing on nouns.

3.1.1.1 Attributes

An attribute is what an object of a class knows. It's an element of data maintained by the object. For example, each object of the Worker class of the project management system may have a name, description, and so forth. These are all attributes.

In a class diagram, you list attributes in the second compartment for a class. The simplest approach is to just list attribute names, but the UML allows you to do much more than that. Consider an attribute for holding a worker's email address. You may start by defining it using the following basic syntax:

EmailAddress

As you go through the development process, you can add detail to this definition in each iteration by asking various questions and capturing more detail about the attribute based upon the answers.

For example, you may ask how many email addresses a worker has. Presuming that a worker may have up to five email addresses, you can update the attribute definition to the following:

EmailAddress [1..5]

Next, you may ask if these email addresses are ordered, perhaps by priority. Presuming that email addresses are not ordered, you can update the attribute definition as follows:

EmailAddress [1..5 unordered]

You may decide to ask the type of data an email address attribute needs to hold. You discover that an email address is a string of characters, and you update the attribute definition to indicate that:

EmailAddress [1..5 unordered] : String

You might then ask if there should be a default value for a worker's email address. Your client suggests using a default value of "No email address", so you update the attribute definition to the following:

EmailAddress [1..5 unordered] : String = "No email address"

Finally, you may ask whether other objects are allowed to access a Worker object's email address. Presuming the answer is that a Worker object's email address is not accessible by other objects, you can update the attribute definition one last time by preceding it with minus sign (-), as follows:

- EmailAddress [1..5 unordered] : String = "No email address"

To summarize, this final attribute definition communicates the following information:

The - symbol

Indicates that the email address attribute is private to an object and thus inaccessible by other objects.

1..5

Indicates that the email address attribute may have from one to five values.

unordered

Indicates that the email address attribute values are not ordered based on any specific criteria.

String

Indicates that email addresses are strings of characters.

"No email address"

Is the initial value of each email address.

Figure 3-2 shows the Worker class from Figure 3-1 with its attributes. A worker has an identification number (ID), a next identification number (NextID), a name, up to five email addresses that are unordered, any number of phone numbers that are ordered, and a password. NextID is underlined to indicate that it is one value, defined at the class level, shared by all objects of the class. The system uses this shared value to ensure that every Worker object has a unique ID number.

Figure 3-2. Worker class with its attributes
figs/Luml_0302.gif

In Figure 3-2, you'll see some syntax I haven't described yet: a number sign (#) at the front of the Password attribute and the keyword ordered in the PhoneNumber attribute. This syntax is described in the next section, Section 3.1.1.2.

Figure 3-3 shows the UnitOfWork class of Figure 3-1 with its attributes. A unit of work has a name and description.

Figure 3-3. UnitOfWork class with its attributes
figs/Luml_0303.gif

Figure 3-4 shows the WorkProduct class of Figure 3-1 with its attributes. A work product has a name, description, and a percentage of completion.

Figure 3-4. WorkProduct class with its attributes
figs/Luml_0304.gif
3.1.1.2 Attribute syntax

In the UML, an attribute is described in a class's second compartment expressed using the following UML syntax:

visibility name [multiplicity ordering] : type = initial_value

in which:

visibility

Is optional, has no default value, and indicates whether the attribute is accessible from outside the class. It may be one of the following:

+

Public visibility; the attribute is accessible from outside its class.

-

Private visibility; the attribute is inaccessible from outside its class.

#

Protected visibility; the attribute is accessible by classes that have a generalization relationship (as discussed in Chapter 2) to its class, but is otherwise inaccessible from outside its class.

Figure 3-2 through Figure 3-4 show that most attributes are private, except a worker's password is protected so that more specific types of workers may use it in whatever manner in which they handle security.

name

Is the name of the attribute you are describing.

multiplicity

Is optional, has a default value of 1, and indicates the number of values an attribute may hold. If an attribute has only one value, the multiplicity, ordering, and square brackets are not shown. Otherwise, the multiplicity is shown as a lower-bound .. upper-bound string in which a single asterisk indicates an unlimited range; for example, 0..* allows from zero up to an infinite number of values. Figure 3-2 through Figure 3-4 show that all attributes except for EmailAddress and PhoneNumber have one value only. A worker may have up to five email addresses and any number of phone numbers.

ordering

Is optional, has a default value of unordered, and is used where the multiplicity is greater than one to indicate whether the values of an attribute are ordered or unordered. Use one of the following keywords:

unordered

Indicates that the values are unordered.

ordered

Indicates that the values are ordered.

Figure 3-2 shows that a worker's five email addresses are unordered and that a worker's phone numbers are ordered.

type

Is optional, has no default value, and indicates the type of data an attribute may hold. If you don't show a type for an attribute, you should omit the colon. The type of an attribute may be another class. In addition, the UML provides the following data types:

Boolean

A true or false value

Integer

An integer number

Real

A real number

String

A sequence of characters

Figure 3-2 through Figure 3-4 show that most of the attributes are strings while a worker's identification number (ID) and next identification number (NextID) are integers, and a work product's PercentComplete attribute is a real number.

initial_value

Is optional, and indicates the initial value of an attribute. By default, an attribute has no initial value. If you do not show an initial value, you should omit the equal symbol (=). Figure 3-2 through Figure 3-4 show that most of the attributes have no initial value. However, a worker's next identification number (NextID) has an initial value of 1, a work product's percent complete has an initial value of 0, and email addresses have an initial value of "No email address".

If you prefer, the UML also allows you to show an attribute using pseudocode or another language. For example, you can use the syntax of Java, C++, C#, or some other programming language.

If an attribute's value is specific to an object, it is known as instance scoped or object scoped. If an attribute is shared by all objects of a class, it is known as class scoped. To indicate that an attribute is class scoped, underline it. Figure 3-2 through Figure 3-4 show that all the attributes are object scoped, except for the worker's next identification number (NextID), which is class scoped.

3.1.1.3 Operations

Recall from Chapter 2 that an operation is what an object of a class can do. It is a specification of a service provided by the object. Recall also that a method is how an object of a class does its processing. It is an implementation of a service provided by the object. For example, each class of the project management system may provide getter and setter operations for its attributes. These getter and setter operations retrieve and set the values for the attributes of a worker, unit of work, work product, and so forth.

Consider an operation for adding an email address to a worker. You may start by defining it using the following basic syntax:

addEmailAddress

As you go through iterations of the development process, you can add detail to this definition by asking questions and capturing additional detail about the operation from the answers to those questions.

For example, you may ask if the addEmailaddress operation requires any parameters: data that is input to or output from the operation. Presuming that the operation requires an email address as input, you can update the operation definition to the following:

addEmailAddress (theEmailAddress)

Next, you may ask what type of data may the email address hold? Presuming that the email address is a string of characters, you can update the operation definition to the following:

addEmailAddress (theEmailAddress : String)

Next, you may ask if there is a default value for the email address. Presuming that the email address has a default value of an empty string, or no characters, you can update the operation definition to the following:

addEmailAddress (theEmailAddress : String = "")

You might then ask whether the email address is simply an input to the operation, an output from the operation, or both. Presuming that the email address is only input to the operation, and thus not modified by the operation, you can add the in keyword preceding the parameter name:

addEmailAddress (in theEmailAddress : String = "")

You may then ask whether the operation returns any type of data. Presuming that the operation returns a Boolean true or false indicating whether the operation was successful in adding the email address to the worker, you can update the operation definition to the following:

addEmailAddress (in theEmailAddress : String = "") : Boolean

Finally, you may ask whether other objects are allowed to access an object's addEmailAddress operation. Presuming that an object's addEmailAddress operation is accessible by other objects, you can precede the operation name in the definition with a plus sign (+):

+ addEmailAddress (in theEmailAddress : String = "") : Boolean

To summarize, this operation definition communicates the following:

The + symbol

Indicates that the addEmailAddress operation is public and is accessible by other objects. The expression inside the parentheses indicates the parameters that hold the values passed to the operation.

The in keyword

Indicates that the parameter is input and may not be modified by the operation.

theEmailAddress : String = ""

Indicates that an email address, which is a string with a default value of an empty string, is passed to the operation.

The Boolean keyword

Indicates that the addEmailAddress operation returns a value of true or false, perhaps indicating whether there is room for the email address to be added to the email address attribute (which holds a maximum of five email addresses).

Figure 3-5 shows the Worker class from Figure 3-1 and Figure 3-2 with its various attribute getter and setter operations. Notice that the getter and setter operations for phone numbers are based on the priority of the phone number such that you specify the priority and set or get the corresponding phone number. Also, notice that the getter operation for email addresses retrieves all of a worker's email addresses, while the setter operation for email addresses simply adds one email address. The create and destroy operations create and destroy worker objects, respectively.

Figure 3-5. Worker class with its operations
figs/Luml_0305.gif

Figure 3-6 shows the UnitOfWork class from Figure 3-1 and Figure 3-3 with its various getter and setter operations to set and retrieve attribute values, and with operations to create and destroy UnitOfWork objects.

Figure 3-6. UnitOfWork class with its operations
figs/Luml_0306.gif

Figure 3-7 shows the WorkProduct class from Figure 3-1 and Figure 3-4 with its various getter and setter operations for its attributes and operations to create and destroy work objects. Notice that Figure 3-7 also shows the attributes of the class.

Figure 3-7. WorkProduct class with its operations
figs/Luml_0307.gif
3.1.1.4 Operation syntax

In the UML, an operation is described in a class's third compartment using the following UML syntax:

visibility operation_name (parameter_list) : return_type

in which:

visibility

Is optional, has no default value, and indicates whether the operation is accessible from outside of the class.

It may be one of the following:

+

Public visibility; the operation is accessible from outside its class.

-

Private visibility; the operation is inaccessible from outside its class.

#

Protected visibility; the operation is accessible by classes that have a generalization relationship (as discussed in Chapter 2) to its class, but is otherwise inaccessible from outside its class.

Figure 3-5, Figure 3-6, and Figure 3-7 show that all the operations are public, except that the operation to set a worker's password is protected so that more specific types of workers or subclasses of the Worker class may use it in whatever manner in which they handle security.

operation_name

Is the name of the operation you are describing.

parameter_list

Is optional, has no default value, and is a comma-separated list indicating the parameters that hold the values passed to or received from the operation. Each parameter is shown as a text string having the following syntax:

kind name : type = default_value
kind

Is optional, has a default value of in, and may be one of the following:

in

Indicates the parameter is input-only, and may not be modified by the operation.

out

Indicates the parameter is output-only, and may be modified by the operation to communicate information to the client that invoked the operation.

inout

Indicates that the parameter is input and may in turn be modified by the operation to communicate information to the client that invoked the operation.

The type and default value are the same as for an attribute's type and initial value, described in the previous section.

type

Is optional, has no default value, and indicates the type of data a parameter may hold. If you don't show a type for a parameter, you should omit the colon. The type of a parameter may be another class. In addition, the UML provides the following data types:

Boolean

A true or false value.

Integer

An integer number.

Real

A real number.

String

A sequence of characters.

default_value

Is optional, and indicates the initial value of a parameter. By default, a parameter has no initial value. If you do not show an initial value, you should omit the equal symbol (=).

Figure 3-5 shows an initial value for the parameter to the addEmailAddress method.

return_type

Is optional, has no default value, and indicates the type of data the operation returns to its caller. If you choose not to show the return type of an operation, you should also omit the colon. Your choices for return type are the same as for a parameter type. Many of the operations shown in Figure 3-5 through Figure 3-7 show a return type.

If you prefer, the UML also allows you to show an operation using pseudocode or another language. For example, you can use the syntax of Java, C++, C#, or some other programming language.

If an operation applies to a specific object, it is known as instance scoped or object scoped. If an operation applies to the class itself, it is known as class scoped. Figure 3-5 through Figure 3-7 show that most of the operations are object scoped. The exceptions are the create operations, which are class scoped. The create operations are used to create objects of a class and are known as constructors. The destroy operations are used to destroy objects of a class and are known as destructors. The create operations are class scoped, because a class is used to create objects of the class; if create were instance scoped, you'd need to somehow create an object before invoking its create operation to create it, which makes no sense. The destroy operation, on the other hand, is object scoped, because it is applied to a specific object that is to be destroyed.

We can combine Figure 3-2 and Figure 3-5 or Figure 3-3 and Figure 3-6 much the way that Figure 3-7 combines the attributes shown in Figure 3-4 with the class's operations. In this way, we can show any combination of attributes and operations based upon what we want to communicate.

Methods, the actual implementations of operations, are not shown on a class, but may be described using other UML modeling techniques.

3.1.2 Objects

As discussed in Chapter 2, an object is a specific concept, or instance of a class, having the characteristics defined by its class, including structural features and behavioral features. For example, the project management system involves various specific concepts, including specific projects, managers, teams, work products, requirements, systems, and so forth. Recall that structural features define what the object knows, and that behavioral features define what the object can do. Structural features included attribute values and links. Behavioral features include operations and methods, which are shared by all the objects of a class. The most crucial aspect of an object is that it has its own identity. No two objects are the same, even if they have the same values for their structural features. For example, even if two worker objects have the same values for their attributes, the objects are unique and have their own identities.

In a UML object diagram, an object is shown as a solid-outline rectangle with two standard compartments separated by horizontal lines. The required top compartment shows the object name followed by a colon followed by the object's class name, and the entire string is fully underlined. Both names are optional, and the colon should only be present if the class name is specified. The optional second compartment shows a list of attributes. The second compartment need only show the specific information you want to communicate using a given diagram; you need not show all of an object's attribute values all the time.

Figure 3-8 shows various objects associated with the classes shown in the previous figures. These objects include the following:

  • Nora and Phillip who are workers

  • Testing that is a unit of work

  • Test that is a work product

  • An anonymous unit of work with the name attribute, Implementation

  • An anonymous work product with the name attribute, System

  • XYZ that is an unspecified object.

Figure 3-8 introduces notation you haven't seen before: some objects have no names and others have no class specified. Objects in a UML diagram that do not have names are referred to as anonymous objects. Objects for which a class has not been specified are referred to as unspecified objects. You may encounter such notation depending on the specific methodology being used for a project.

Note that the object names in Figure 3-8 are all fully underlined. You'll also see specific attribute values. I'll discuss attribute values further in the next section.

Figure 3-8. Objects
figs/Luml_0308.gif
3.1.2.1 Attribute values

An attribute value is the value an object of a class knows for an attribute. In the UML, an attribute value is described in an object's second compartment. For example, each Worker object of the project management system may have a value for its name.

Consider an attribute value for holding a worker's email addresses. You may define it using the following syntax:

- EmailAddress [1] : String = "ph@myorg.org"

This definition communicates the following:

The - symbol

Indicates that the email address attribute is private and accessible only by the object.

[1]

Indicates that this is the first email address value, because there are multiple email address values.

String

Indicates that the email address is a string of characters.

"ph@myorg.org"

Indicates the value of the email address attribute.

Following is the general syntax to use for defining attribute values:

visibility name [index] : type = value

The syntax elements are the same as for the attributes of a class.

3.1.2.2 Operations

Because the operations and methods of a class are shared by all the objects of the class, operations are not shown on each object. For example, Figure 3-8 shows that both Nora and Phillip are workers, and therefore they share the operations and methods of the Worker class. There is no need to show the operations on each object, as the operations will be unnecessarily repeated each time. To determine the operations of an object, refer to that object's class.