Objects and Classes
In UML classes are represented by icons of the form:
A class diagram shows classes and dependencies between classes.
A class diagram has three different interpretations depending on the development phase. In the analysis phase classes are concepts. In the design phase classes are interfaces. In the implementation phase classes are implementation classes.
Here is an example of a class diagram adapted from [FOW-2]:
In general, a dependency from class A to class B indicates that changes to A may cause changes to B. Dependencies are indicated by dashed arrows. For example, a View window depends on the Document it displays:
There are three special types of dependencies: associations, generalizations (specializations), and realizations (implementations).
Associations
Assume a certain school employs four teachers: Teacher = {a, b, c, d}. Assume this school offers six courses: Course = {x1, x2, x3, x4, x5, x6}. There are 24 possible pairs of teachers and courses (i.e., |Teacher x Course| = 4 * 6 = 24). In a particular semester the teaches relationship contains some subset of these 24 pairs:
If we think of Teacher and Course as classes, then in UML terminology the teaches relationship is called an association and the pairs in the teaches relationship are called links or association instances.
In a class diagram an association is represented by a line segment connecting two class icons. The line segment may be labeled by the name of the association. Each end of the line segment is called a role. A role may be decorated by a name, a multiplicity, and/or an arrowhead:
Unless otherwise specified, the name of the role is the name of the class it connects to. Multiplicity is a range of integers: m..n. It indicates the number of instances of the class that may be linked to one instance of the other class. A barbed arrowhead indicates navigability, the ability to find out what object another object is linked to.
In C++ a link might be represented as a pointer:
// from course.h
class Course
{
public:
void addTeacher(Teacher*
t) { taughtBy.push_back(t); }
void remTeacher(Teacher*
t) { taughtBy.remove(t); }
list<Teacher*>
getTeachers() { return taughtBy; }
// etc.
private:
list<Teacher*>
taughtBy;
// etc.
};
Aggregation and Composition
Aggregation is a special type of association, and composition is a special type of aggregation.
Aggregation is the relationship between a whole and its parts. Composition adds the restriction that the parts cannot be parts of more than one whole at a time. Also, a composition is responsible for the creation, management, and destruction of its parts.
Aggregation is indicated by a hollow diamond on the aggregate end of the association. Composition is indicated by a solid diamond on the composite side of the association. Here are a few examples:
Generalization/Specialization
A certain company has 5 employees: Employee = {e1, e2, e3, e4, e5}. Every employee has a name, salary, and social security number. Three of the employees are secretaries: Secretary = {e1, e2, e3}, the other two are executives: Executive = {e4, e5}. In addition to name, salary, and social security number, secretaries are employees with secretarial skills such as typing. In addition to name, salary, and social security number, executives are employees with decision making skills.
If we think of Employee, Secretary, and Executive as classes, then the subset relationship between Secretary and Employee and the subset relationship between Executive and Employee are called generalizations. In UML notation a generalization is an arrow with a triangular head:
In C++ generalization can be expressed by base classes:
A realization is the relationship between an interface and a class that implements it. This doesn't have too much meaning during the analysis phase, but during the design and implementation phase, interfaces and realizations play an important role.
An interface(or ADT) is a class without attributes or operation implementations. To put it another way, an interface is merely a collection of operation signatures (a.k.a. headers, prototypes). Although an object must instantiate a proper class, an object handle (i.e., a pointer, reference, OID, etc.) need only be associated with an interface. Thus, a client can write programs that perform operations on a handle without knowing exactly what class of object the handle is currently attached to. Indeed, the same handle may be attached to objects of different classes at different times during the execution of the program. Not only is this a wonderful abstraction mechanism (i.e., the interface is separated from the implementation), it is also allows programmers to write polymorphic programs (i.e., the behavior of the handle can only be known at runtime, when the object the handle is attached to is known.)
Java allows programmers to explicitly declare interfaces:
class Blimp implements Airship
{
void takeoff()
{ ... }
void fly()
{ ... }
void land()
{ ... }
}
class Blimp: public Airship
{
public:
void takeoff()
{ ... }
void fly()
{ ... }
void land()
{ ... }
};
Meta Classes, Power Classes, and Stereotypes
Recall that if A is a set:
The UML Meta Model
Meta classes are a little more general than power classes. Anything in the solution domain may be an instance of a meta class. For example, we can think of all the UML elements we have seen as instances of various meta classes. A class diagram made up of meta classes is called a meta model: