Saturday, April 5, 2008

Better Class Diagrams

Use a Class Diagram to model the relationships between classes in the object model.

The basic class relationships include:

  • Association: A non-specific, bi-directional relationship between two or more classes describing a group of links with common structure and semantics.  Most associations are binary.
  • Aggregation: Specifies a whole-part (or “a-part-of”) relationship between two classes. It also can be expressed as a “comprises” or “is comprised of” relationship since the containment does not have to be a physical containment.  For example, an a fuel injector is a part of an engine, it is physically contained in the engine.  A CarRentalFleet consists of many Cars.  While the cars are not physically contained in the fleet, they are part of the fleet.  Their relationship is an aggregation association.
  •         Dependency: Indicates a client-supplier relationship between two classes. 
  • Inheritance: Specifies a generalization-specialization (“is-a” or “is-a-kind-of”) relationship between two classes.  A class relationship that allows a specialized class (a subclass) to share the attributes and methods defined for one or more generalized classes (superclasses).  When the class shares attributes and behavior from only one superclass the relationship is referred to as single inheritance.  When the class shares attributes and behavior from more than one superclass it is referred to as multiple inheritance.

The definition of inheritance relationships can have significant ramifications for the object model. 

Example

The example shows some of these associations for a car rental agency:

Method

  1. Define association relationships
  2. Define inheritance relationships

 

 

 

1. Defining Class Associations

To build a class diagram, assess the associations:

  • Define association relationships,
  • Define aggregation relationships,
  • Define dependency relationships,
  • Assign multiplicity.

Defining Association Relationships

Look for non-specific, bi-directional relationships between two classes.  For example, in the problem domain of a car rental agency, the car rental agency manages a rental account, and a rental account is managed by a car rental agency.  They have an association relationship. Association relationships are shown by drawing a line between two classes with a semantic dependency.

Name association relationships with descriptive and concise names.  Ensure the name is consistent with the directionality of the association.  In general, an association name should suggest traversal from the “source class” to a “target class.”  For example, name the association between CarRentalAgent and Customer “serves” to indicate that CarRentalAgent (the source class) serves Customer (the target class).  In a bi-directional association like this, the choice between which class is the source and which is the target is somewhat arbitrary.  The association name isServedBy to indicate that CarRentalAgent is the target and Customer is the source.  While there are no strict rules for this, in general (as in writing prose) the active voice (serves) is preferable to the passive voice (isServedBy).

Defining Aggregation Relationships

Aggregation is a special kind of association.  Examine the classes and their associations that specify a whole-part (is-part-of) semantic dependency between two classes.  This whole-part relationship is called aggregation.  For example, in a car rental domain the CarRentalFleet consists of a collection of Car objects. Aggregation relationships are indicated by a line with a diamond on one end, where the class at the end with the diamond is the container of the class at the other end.  Or, expressed differently, the class at the end with the diamond is comprised of classes at the other end.  The containment does not have to be physical.

The CarRentalFleet class is called the aggregate class and the Car class is called the part class.

Defining Dependency Relationships

A dependency association indicates a client-supplier relationship between two classes. For example, in the car rental problem domain an AutomatedCarReservationService class supplies reservation services to class Customer.  A dependency relationship is shown as a dashed line from the client to the supplier.

Assigning Multiplicity

Assign multiplicity (also known as cardinality) to associations.  The multiplicity of an association identifies how many instances of one class can be associated with a single instance of another related class.

The three most common types of multiplicity associations are:

  • one-to-one,
  • one-to-many,
  • many-to-many.

A one-to-one multiplicity association indicates that for each instance of the source class, there is zero or one instance of the target class.  The one-to-one relationship can be expressed specifically as ‘one-to-optionally-one’ to indicate that a zero occurrence is allowed; or, as ‘one-to-one’ to indicate that exactly one occurrence of the target is associated with the source.

A one-to-many multiplicity association indicates that for each instance of the source class, there are zero or more instances of the target class.  For example, in the sample problem there are many instances of RentalRequest for each instance of CarRentalAgent.

A many-to-many multiplicity association indicates that: 1) for each instance of the source class, there are zero or more instances of the target class; and 2) conversely, for each instance of the target class, there are zero or more instances of the source class.  For example, in a car rental agency there are many instances of Customer for each instance of CarRentalAgent.  Conversely, there can be multiple instances of CarRentalAgent for each instance of Customer.

 

2. Defining Class Inheritance Relationships

Diagramming the inheritance relationships helps to communicate structure and inheritance of an object model. The diagram is also a tool to help abstract and simplify the model. Inheritance relationships organize classes into generalization-specialization (superclass-subclass) hierarchies; they provide a basic re-use mechanism for sharing attributes and operation

Method

Look for classes from both a top-down and bottom-up approach:

  • Look for classes with similar attributes, relationships and/or operations and generalize a superclass for them.
  • Search for classes that seem highly generalized (suggesting a superclass) and deduce specialized classes (subclasses) from them.

Draw the hierarchy diagram using the same conventions as for an Entity Relationship diagram. Treat each class as an entity. Treat subclasses in the same way as subtypes. A simple example illustrates the diagrammed inheritance relationship.

A big difference between entities and objects in defining relationships is that object relationships emphasize behavior, not just attributes. Creating a superclass just to handle common attributes is not good practice.

Consider the following checklist to assess inheritance.

Inheritance Relationship Checklist

Sample Checklist Template

INHERITANCE RELATIONSHIP CHECKLIST

 

Yes

No

N/A

Remarks

Use the following to identify when an enumerated attribute should be used instead of inheritance:

Is the object’s identity more important than just an attribute value?

 

 

 

 

Does the object have behavior essential to the business?

 

 

 

 

Is there more than one simple attribute for this proposed subclass?

 

 

 

 

Do instances have different behavior and attributes when a value is given to an enumerated attribute?

 

 

 

 

If the answer is no to any of the questions, model as an enumerated attribute of the class, not as a subclass. The element that would have been the discriminator among subclasses becomes an enumerated attribute of the class. Typically "IF-THEN-ELSE" or CASE logic is used to handle the differences in behavior based on the enumerated attribute.

Use and expand as needed...

Consider Generalizations

Look for a super class that you can generalize from the classes in the evolving object model.

Consider classes that have similar names (e.g., ending in Service) and similar attributes. These classes probably have different behavior (e.g., different initializations and different operations), but their common attribute structure suggests that they are good candidates for generalization into a superclass GeneralizedService (a more specific name would be used in a real model). Derive the attributes for the superclass GeneralizedService by intersecting the attributes of the subclasses.

Deduce Specializations

Search for classes that seem highly generalized (suggesting a superclass) and deduce specialized classes (subclasses) from them.

Consider, for example, a requirement to accommodate both individual and corporate travel accounts. This difference could be modeled trivially using an attribute; however, if there are substantive differences between individual and corporate travel accounts, then a better mechanism is the inheritance structure. Consequently, derive two subclasses from TravelAccount: CorporateTravelAccount and IndividualTravelAccount.

Tips and Hints

Don’t inherit from a superclass just so you can access its private attributes and operations. That is, ensure that the subclass is really a specialization or refinement of the superclass, an that inheritance is not just a mechanism to allow a largely unrelated class to use a method. Make sure that the inheritance relationship promotes re-use and is consistent with the rest of the object model.

Make sure that the attributes and operations of superclasses are being well used by their subclasses. Look for superclasses that are under- or over-used, and balance the inheritance hierarchy accordingly.

Be careful about using multiple inheritance. The inappropriate use of multiple inheritance can lead to class inheritance hierarchies that are difficult to understand. Also consider that multiple inheritance is not supported by all OOP languages (e.g., Smalltalk).
An abstract class should only inherit from another abstract class, not from a class having instantiations.

 

No comments: