Login

Classes

In this article you will learn about the Unified Modeling Language (UML) by examining basic modeling of things and concepts in the real world. It is excerpted from the book Fast Track UML 2.0, written by Kendall Scott (Apress, 2004; ISBN: 1590593200)

LET’S BEGIN OUR LOOK AT THE DETAILS of the Unified Modeling Language (UML) by exploring how we do basic modeling of things and concepts in the real world.

Classes and Objects

A class is a collection of things or concepts that have the same characteristics. Each of these things or concepts is called an object.

An object that belongs to a particular class is often referred to as an instance of that class. You can think of a class as being an abstraction and an object as being the concrete manifestation of that abstraction.

The class is the most fundamental construct within the UML. Reasons why this is so include the following:

Classes define the basic vocabulary of the system being modeled. Usin g a set of classes as the core glossary of a project tends to greatly facilitate understanding and agreement about the meanings of terms.

Classes can serve as the foundation for data modeling. Unfortunately, there is no standard for mapping between a set of classes and a set of database tables, but people like Scott Ambler1 are working to change that.

Classes are usually the base from which visual modeling tools—such as Rational Rose XDE, Embarcadero Describe, and Sparx Systems’ Enterprise Architect—generate code.

The most important characteristics that classes share are captured as attributes and operations. These terms are defined as follows:

Attributes are named slots for data values that belong to the class. Different objects of a given class typically have at least some differences in the values of their attributes.

Operations represent services that an object can request to affect behavior. (A method is an implementation of an operation; each operation of a given class is represented by at least one method within each of the objects belonging to that class.)

The standard UML notation for a class is a box with three compartments. The top compartment contains the name of the class, in boldface type; the middle compartment contains the attributes that belong to the class; and the bottom compartment contains the class’s operations. See Figure 1-1.

Figure 1-1. Class notation

You can, however, show a class without its attributes or its operations, or the name of the class can appear by itself (see Figure 1-2).

Figure 1-2. Alternate class notations

The level of detail you choose to show for your classes depends on who is reading the diagrams on which they appear. For example, a stakeholder who’s focused on the “big picture” is probably interested only in the names of the classes, while a developer working at a more detailed level probably wants to see a full set of attributes and operations. You can also “mix and match” nota tions in a given context.

Figure 1-3 shows some examples of classes.

Figure 1-3. Sample classes

The names of the classes, attributes, and operations in Figure 1-3 adhere to conventions that aren’t carved in stone but are in fairly wide use. These conventions are as follows:

Class names are simple nouns or noun phrases. Each word is capitalized.

Attribute names are also simple nouns or noun phrases. The first word is not capitalized, but subsequent words are. Acronyms tend to appear in all uppercase letters.

Operation names are simple verbs. As with attributes, the first word is not capitalized and subsequent words are; acronyms tend to appear in all uppercase letters here as well.

Note that all words in class, attribute, and operation names are generally run together, as shown in Figure 1-3.

Whether you choose these simple conventions—or more elaborate ones— the naming of classes, attributes, and operations should be consistent with the language or platform that you’re using or with your company-specific coding standards.

NOTE The title attribute of the Book class has an associated data type(String), whereas the other three attributes in the figure (emailAddress, ID, and password) don’t have types. Note also that each of the three operations (verifyPassword, assignRating, and computeAvgRating) has a different appearance. There are various kinds of details that you can attach to attributes and operations. These are explored in the section “Attribute and Operation Details,” later in this chapter.

It’s often desirable to define explicit responsibilities for a class. These represent the obligations that one class has with regard to other classes. Figure 1-4 shows how you can use an extra compartment within a UML class box to indicate responsibilities for a class.

Figure 1-4.Class responsibilities

The idea of assigning responsibilities to classes is at the center of Class-Responsibility-Collaboration (CRC) cards.2 This idea is also central to Responsibility-Driven Design.3

As development proceeds, responsibilities tend to get explicitly addressed by operations as classes get refined. So, you shouldn’t be surprised if you don’t see the responsibility compartment in later versions of models that include class boxes.

NOTE You can also extend a class box with other compartments that contain whatever information you want to see. You find examples of these other compartments later in the book.

The notation for an object takes the same basic form as that for a class. There are three differences between the notations, as follows:

Within the top compartment of the class box, the name of the class to which the object belongs appears after a colon. The object may have a name, which appears before the colon, or it may be anonymous, in which case nothing appears before the colon.

The contents of the top compartment are underlined for an object.

Each attribute defined for the given class has a specific value for each object that belongs to that class.

Figure 1-5 shows the notation for both a named object (left) and an anonymous object (right).

A simple yet effective way to discover classes uses a technique variously known as noun/verb analysis and grammatical inspection. This involves poring through high-level requirements documents, marketing materials, and other materials that provide insight into the problem domain (in other words, the arena defined by the problem that the new system is supposed to solve). See Use Case Driven Object Modeling with UML4 for an example of how to perform grammatical inspection using a set of text requirements.

Many people use rapid prototyping as a device for exploring requirements with users. Let’s see how we might use a prototype HTML page for an Internet bookstore to discover a small subset of the classes we’ll need in modeling the bookstore as a whole. We start with a page that displays the details of a particular book.

A quick mental review of the page reveals the following obvious candidates for classes:

There’s a Book, of course, and at least one Author.

There’s a Publisher.

There may be one or more Reviews of the Book. These Reviews fall into one of two categories: EditorialReviews and CustomerReviews. (You see how to make this distinction in Chapter 2.) Each Review has a Reviewer associated with it.

If we move ahead and envision the viewer of this page purchasing the Book, the following other potential classes come into view:

The viewer becomes a Customer, with an associated Account.

The Book becomes part of an Order.

The Order has to have BillingInformation and ShippingInformation in order for the bookstore to get paid and to ship the book.

Analyzing a little more deeply reveals the need for the following two other classes:

A Book can have more than one Author, as I’ve noted, but an Author can have more than one Book, too. In the interest of avoiding many-to-many relationships, we need a BookAndAuthor class. (You see how to represent this class in Chapter 2.)

The bookstore uses various shipping companies, so there needs to be a Shipper class.

The result, then, is the following set of nouns and noun phrases:

Account

Author

BillingInfo

Book

BookAndAuthor

Customer

CustomerReview

EditorialReview

Order

Publisher

Review

Reviewer

Shipper

ShippingInfo

NOTE This example is representative of a fundamentally sound idea: Find as many nouns and noun phrases as possible to start, and only analyze, refine, and expand the list later. Regardless of how you go about it, though, discovering classes is an excellent way to get your modeling off to a good start.

{mospagebreak title=Attribute and Operation Details}

The UML offers a variety of constructs that allow you to specify details for attributes and operations. These constructs are discussed in the following subsections.

Visibility

Encapsulation is the principle of data hiding: An object hides its data from the rest of the world and only lets outsiders manipulate that data by way of calls to the object’s methods. The degree to which the elements of a class are encapsulated within that class depends on the level of visibility that’s been assigned to the elements. The visibility of an attribute or an operation specifies whether objects that belong to other classes can “see” that attribute or operation.

The UML supports the following four levels of visibility:

Package visibility (shown with a tilde [~]) means that objects belonging to any class in the same package as the given class can see and use the given class it. (Packages are discussed in Chapter 5.)

Public visibility (+) means that objects belonging to any class can use the given attribute or operation.

Protected visibility (#) means that only objects that belong to subclasses of the given class (at any level below that class) can use the attribute or operation. (Subclasses are discussed in Chapter 2.)

Private visibility (–) means that only objects belonging to the class itself can use the attribute or operation.

The assignRating operation of the CustomerReview class is public, which means that objects of any other class can use it. The record operation of Review is protected, so CustomerReview objects and EditorialReview objects can use it, and objects of any subclasses of those two classes would be able to use it as well, but objects of classes outside that hierarchy cannot use record. The emailAddress, ID, and password attributes of Account are private: Only Account objects have access to these attributes. Similarly, CustomerReview objects are the only ones that can use the computeAvgRating operation.

NOTE The Review class and its record operation are abstract. Abstract classes and operations, which appear in italics to differentiate them from “concrete” classes and operations, are discussed in the section “Abstract Classes,” later in this chapter.

The rectangular brackets surround optional items, which means that only the name is required. However, UML diagrams generally show details about attributes once serious design work commences on a project.

Visibility was discussed in the previous section. A forward slash appearing before the name of the attribute means that a value of the attribute can be derived from the values of one or more other attributes. For instance, if an object has an attribute named dateOfBirth and another attribute named age, the value of the latter attribute could be computed based on the value of the former.

Examples of built-in attribute data types include Double, Int (short for Integer), and String (which appeared in Figure 1-3). An attribute type can also be a user-defined type or the name of a class.

Multiplicity indicates how many of one thing can exist relative to another thing. A multiplicity expression can take several forms, including the following:

A fixed value (such as 1 or 3)

An asterisk (*), which means “many”

A range of values, expressed as lower..upper (for instance, 0..1 or 3..*)

A set of values (for example, [1, 3, 5, 7])

A multiplicity value on an attribute indicates how many instances of that attribute are present for each instance of the class. The multiplicity of an attribute appears between square brackets after the attribute name.

A default value of an attribute for a class means that each instance of that class has that initial value for the given attribute.

The most important property you can attach to an attribute declaration is readOnly, which indicates that you can add possible values for the attribute, but you can’t change existing values.

Figure 1-7 shows details of some of the attributes of an example class.

Figure 1-7. Attribute details

NOTE An object belonging to the Account class can have from one to three email addresses. Each Account object has an ID that can’t be deleted; you might think of this as being the equivalent of the key within a database table. And, there’s an initial value for an Account object’s password, which the Customer is likely to change but which is useful in case the Customer forgets to define a password when he or she sets up an Account.

More About Operations

The full form of a UML operation declaration is as follows:

[ visibility] name [( parameter-list)] [{ property-string}]

As with attributes, the rectangular brackets surround optional items.

A discussion of visibility appeared earlier in this chapter. The parameters of an operation, which appear in a list separated by commas, represent the data provided by the caller of the operation, the data that the operation returns to the caller, or both. The full form of a parameter declaration is as follows:

[ direction] name : type [ multiplicity] [ = default-value]

A parameter can have one of the following three directions:

in (The operation can’t modify the parameter, so the caller doesn’t need to see it again.)

out (The operation sets or changes the value of the parameter and returns it to the caller.)

inout (The operation uses the value of the parameter and may change the value; the caller expects to see an inout parameter again.)

Types work the same way for parameters as they do for attributes. See the section “More About Attributes,” earlier in this chapter, for a discussion of multiplicity. A default value of a parameter for an operation means that each call to that operation includes that value for the given parameter.

One property that you can attach to an operation declaration is isQuery, which indicates that the operation doesn’t change the values of any attributes. There are three other properties that relate to concurrency, which has to do with how a method that implements a given operation responds in the context of multiple threads of activity. The three possible concurrency values are as follows:

concurrent (Multiple method calls, from multiple threads, may come in simultaneously to the method, and these calls can all proceed concurrently.)

guarded (Multiple calls may come in simultaneously, but only one can pro ceed at a time.)

sequential (Only one call may come in at a time.)

Figure 1-8 shows some details of operations belonging to an example class.

Figure 1-8.Operation details

The checkAvailability operation receives a Book object (see Figure 1-3) and returns a value of the user-defined type OrderStatus. The isFulfilled operation is a query that returns True if everything the customer ordered is in place or False otherwise.

You can add precision to your modeling of operations by indicating constraints, which specify conditions that must hold true in a given context. You show a constraint as a Boolean expression between curly brackets.

NOTE The UML defines a separate language, called the Object Constraint Language (OCL), that you can use to specify constraints. Using the OCL enables you to reach a certain level of rigor in your modeling without side effects. In other words, the evaluation of OCL expressions can’t alter the state of the executing system. See The Object Constraint Language5 for more information about the OCL.

Two kinds of constraints are of particular interest in the context of operations: preconditions and postconditions.

A precondition specifies a condition that must hold true before an operation starts executing. Figure 1-9 shows an example of a precondition contained within a note, which you can use to record comments about a model without affecting the content of the model.

Figure 1-9. Precondition

Note that the triangular brackets (called guillemets) around the word precondition indicate the presence of a stereotype. This is a mechanism for building a modeling construct that isn’t identified in the core UML but that’s similar to things that are part of the core. Stereotypes of various kinds appear throughout this book; some of them are built in to the UML, while others are user defined.

A postcondition specifies a condition that must hold true before an operation starts executing. Figure 1-10 shows an example of a postcondition.

Figure 1-10. Postcondition

Classes

You can also specify which exceptions a given operation raises. One way to do this is to create a note with «exception» at the top followed by a list of exception types relevant to the operation. (You read about other ways to specify exceptions in Chapter 6.)

{mospagebreak title=Abstract Classes}

An abstract class is a class that can’t have any instances.

Abstract classes are generally designed to capture operations that subclasses inherit. The idea is that the operations defined for an abstract class are relatively general, and each class that inherits these operations refines and expands upon them. (You explore inheritance in Chapter 2.)

In UML notation, the name of an abstract class appears in italics (see Figure 1-11).

Figure 1-11. Abstract class

NOTE Figure 1-11 adds an abstract operation, record, to the Review class. CustomerReview and EditorialReview both inherit this operation, but the operation works differently in the context of each class.

You can also use an «abstract» stereotype for readers of the model who might not realize the significance of the italics.

Active Classes

An active class is a class that represents an independent flow of control, such as a process or a thread.

The class box for an active class has thin vertical bars just inside the borders, as shown in Figure 1-12.

Figure 1-12.Active class

The instances of an active class are called active objects.

Interfaces, Ports, and Connectors

An interface is a collection of operations that represent services offered by a class or a component. (A discussion of components appears in Chapter 9.) By definition, all of these operations have public visibility. (See the section “Visibility,” earlier in this chapter.)

One of the key tenets of object orientation is the separation of an interface from the details of how the exposed operations are implemented as methods. The interface specifies something like a contract that a class must adhere to; the class realizes (or provides a realization for) one or more interfaces.

The UML defines two kinds of interfaces: provided interfaces and required interfaces.

Provided interfaces are interfaces that a class provides to potential clients for the operations that it offers (such as objects belonging to other classes). There are two ways to show a provided interface. One way is called “lollipop” notation: The interface is a circle attached to the class box with a straight line. The other way involves defining the interface using a class box and the built-in «interface» stereotype, and then drawing a dashed line with a triangle at the end that has the interface.

Figure 1-13 shows two examples of provided interfaces, using both notations.

Figure 1-13.Provided interfaces

Setting up a Password Handler interface to the Account class provides the flexibility to use different encryption algorithms in the implementation of the operation that stores customer passwords. Along the same lines, the Inventory Handler interface allows elements of the system to interact with objects belonging to the Inventory class without having to know whether the inventory system uses FIFO (first in, first out), LIFO (last in, first out), or some other method of handling inventory.

Required interfaces are interfaces that a class needs to fulfill its duties. The symbol for a required interface is a half-circle, as shown in Figure 1-14.

Figure 1-14. Required interfaces

Instances of the Order class use Retrieve Books in fulfilling the given order and Retrieve Tracking Info if the Customer that placed the order wants to track the order’s shipping history. (More detail about these interfaces appears in the following paragraphs.)

You can also show one class providing an interface that another class requires, using “ball and socket” notation, where the ball represents the provided interface and the socket indicates the required interface. Figure 1-15 shows an example.

Figure 1-15. Provided/required interface

The Inventory class provides the Retrieve Books interface that the Order class requires, as shown in Figure 1-14.

A port specifies a distinct interaction point between a class and its environment. Ports group provided interfaces and/or required interfaces in two ways. They serve as focal points through which requests can be made to invoke the operations that the class makes available. They also serve as gateways for calls that the class makes to operations offered by other classes.

A port appears as a small square on the boundary of the class box. Interfaces are connected to a port via connectors, which are simple straight lines. Figure 1-16 shows two example ports, one with a name and one without.

Figure 1-16. Ports and connectors

An instance of the Order class receives a request to fulfill the actual order that the instance represents via the Perform Fulfillment interface. The Order instance uses the Retrieve Books interface in meeting this request. After the given order is shipped, the associated Customer may request tracking information via the Provide Tracking Info interface. The Order instance, in turn, uses the Retrieve Tracking Info interface to acquire the necessary information to return to the Customer.

{mospagebreak title=Internal Class Structure}

The behavior of a class can be partly or fully described by a set of objects that the class references and/or owns. Each of these objects is called a property of the class.

Figure 1-17 shows that the GeneralLedger class has three properties: Posting is owned by composition, while PostingRule is “owned” by aggregation. (See the section “Aggregation” in Chapter 2 for definitions of these terms.)

Figure 1-17. Properties

A GLAccount instance owns the Postings made to it, which is why that relationship is a composition. A PostingRule, on the other hand, exists independent of any particular GLAccount instance, which is why that relationship is an aggregation.

An object that is contained by composition is also referred to as a part. Figure 1-18 shows the GeneralLedger class as having two parts.

Figure 1-18. Parts

Note that the notation for a part can also contain a multiplicity value (see the section “More About Attributes,” earlier in this chapter). This value can appear in the upper-right corner of the object box or in square brackets next to the object name.

Ports can be connected to parts within classes, as shown in Figure 1-19 (see the section “Interfaces, Ports, and Connectors,” earlier in this chapter). Each part provides the functionality that external entities request via the associated port.

Figure 1-19. Ports and parts

Anyone in the Accounting department who needs the current balance of a given GLAccount accesses that instance via the Retrieve Balance interface. The software that handles the posting of journal entries goes through the Post Journal Entry interface in order to create an instance of the Posting class, which posts to a particular GLAccount.

Figure 1-19 is an example of a composite structure diagram. This type of diagram shows the internal structure of a class or a collaboration (see the next section, “Collaborations”).

A special kind of port, called a behavior port, passes requests for specific behavior to the instance of the given class itself, rather than to any instances that the class may contain. Figure 1-20 shows the symbol for a behavior port.

Figure 1-20. Behavior port

Collaborations

A collaboration is a description of a named structure of classes. Instances of these classes each perform some specialized function (in other words, each serves a particular role). Taken together, these instances collectively accomplish some desired functionality that’s greater than the sum of the parts.

The name of a collaboration should be a simple noun phrase that communicates the essence of what the collaboration does. The symbol for a collaboration is an ellipse with a dashed outline. Figure 1-21 shows two example collaborations.

Figure 1-21. Collaborations

You can also show the internal structure (in terms of instances) of a collaboration, as shown in Figure 1-22. The lines between instances represent connectors—and thus communication paths.

Figure 1-22. Collaboration with internal structure

The Proxy collaboration is actually an example of a design pattern.6 The names before the colons are those that the pattern specifies; the names after the colons are names, defined by the modeler, for entities that are playing the specified roles.

A Customer retrieving information about his or her Order is presented with an OrderInterface in the form of an HTML page. This interface provides the Customer with an OrderProxy that stands in for the actual Order instance. This is necessary because Order instances are responsible for directing system processes (see the section “Active Classes,” earlier in this chapter) and thus shouldn’t be directly accessible by Customers. The OrderProxy does access the Order as necessary for information, without disrupting system operations.

Figure 1-22 is another example of a composite structure diagram.

A collaboration occurrence is the application of the pattern described by a particular collaboration to a specific situation that involves specific classes or instances playing the roles of that collaboration.

The notation for a collaboration occurrence is comparable to that of an object: the name of the occurrence, a colon, and the name of the collaboration. If the occurrence represents some behavior offered by a class, the occurrence is connected with the class using a represents dependency. Figure 1-23 shows an example of this dependency.

Figure 1-23. Collaboration occurrence

{mospagebreak title=Other Stereotypes on Classes}

There are other built-in stereotypes that may prove useful in helping you define classes. These stereotypes are as follows:

Two stereotypes differentiate between primary and secondary logic or control flow. The «focus» stereotype signifies that a class provides primary logic; the «auxiliary» stereotype signifies that a class supports one or more «focus» classes.

Within Figure 1-24, the GLReport class contains logic for formatting and printing a report that contains information provided by the General Ledger class.

Figure 1-24. Auxiliary and focus stereotypes

Three stereotypes signify sets of values that have no identities and that can’t be changed by operations.

The «dataType» stereotype is the “parent” stereotype. Figure 1-25 shows two examples of user-defined data types.

Figure 1-25. Data types

The «enumeration» stereotype signifies an ordered list of literals. Figure 1-26 shows an example of a user-defined enumeration.

Figure 1-26. Enumeration

This enumeration might be a useful alternative to the BookAndAuthor class that appeared earlier in the chapter. If that class weren’t present, it’s likely that the Author class will have an AuthorRole attribute.

The «primitive» stereotype signifies a data type built in to the UML. There are four primitive types: Boolean, Int, String, and UnlimitedNatural. (The latter is equivalent to “real.”)

The «utility» stereotype signifies that the attributes and operations that belong to a class all have class scope—in other words, the attributes and operations define data, or operate on data, for the class as a whole, as there are no instances of the class.

Two stereotypes offer a way to differentiate classes when you start modeling implementation.

The «specification» stereotype signifies that a class specifies the characteristics of a set of objects without defining the physical implementation of those objects.

The «implementationClass» stereotype signifies that a class provides a static physical implementation of its objects. An implementation class is usually associated with a static class within a programming language, such as C++.

You can use «stereotype» itself as a stereotype to signify that a class is itself a stereotype that can be applied to other elements of your model.

Within Figure 1-27, the class HTMLPage also serves as a stereotype that applies to FormPage and InformationalPage.

Figure 1-27. Stereotype as stereotype

The «metaclass» stereotype signifies that all instances of a class are them selves classes. For example, Class is the metaclass of classes you’ve seen to this point, such as HTMLPage. This is useful if you’re exploring more expansive ways to expand the UML. Unfortunately, metamodeling is beyond the scope of this book.

Looking Ahead

In Chapter 2, you look at the various kinds of relationships in which classes can be involved. The combination of classes and relationships forms the heart of the UML’s structural modeling constructs.

6 Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software (Boston, MA: Addison-Wesley, 1995). Note that this group of authors is often referred to as the “Gang of Four.”