Object-Oriented Design: How-To

Note: this is one possible process; there are many variants. Please refer to one of the many excellent references on Object-Oriented Design. Here's some informal advice.
  1. Identify the classes in the solution domain.
  2. Do a grammatical parse of the problem requirements (use cases) for nouns and noun phrases.

    List all candidates you can think of, then prune to an essential set that covers all the requirements.

    Identify collection classes (e.g. List, Queue) for managing collections of items.

    Research class libraries for classes that you can use or inherit from. Don't reinvent the wheel; use proven code.

    Keep in mind the distinction between classes and objects (instances of classes). E.g., a corvette would be an object of type vehicle or car, it is unlikely that corvette would be a class.

    Don't worry about UI classes at this point.
     

  3. Identify the attributes associated with each class.
  4. Attributes are often nouns from the candidate classes list that got pruned.
    Attributes become the instance variables in a class.
    Most attributes will come directly from the data dictionary.
     

  5. Identify the responsibilities (methods) associated with each class.
  6. Identify the operations suffered by and required of each class. For example, if you are considering a Stack class, ask: "What can I do to a stack? What can happen to a stack?"

    Focus your thinking on one class without considering its environment. For example, addRecord is a never a method on the Record class.

    Don't think about which procedures are going to use the stack or what is going to be pushed on the stack.

    Don't think about data structures or algorithms. Those decisions are best left until detailed design unless there is a feasibility problem.

    Look through the problem requirements for verbs. These often map directly to a method.

  7. Determine the relationships among the classes in your solution.
  8. Read about class relationships.

    This is the hardest part of design. There are many decisions to make:

    Inheritance or Object Composition?

    Consider:
    Inheritance allows programmer to modify operations by overriding them.
    Inheritance relationships can be easily extended in the future.
    Inheritance exposes the internal structure to it's subclasses - with association, the objects remain encapsulated.
    Inheritance carries an assumption of substitutability, promoting a versatile design.
    Composition is simpler.
    Composition allows for implementation independence.
    Composition classes can't modify operations by overriding, thus the interface is more stable.
    Learn more: [Summary]  [Inheritance Critique]   
    Inheritance or Interface?
    Consider: Inheritance allows for sharing structure and behavior, Interfaces allow for sharing behavior.
    Aggregation or Dependency?
    Consider: Does one class use another, or does it aggregate another?

    Be sure to document the rationale for your decisions in the Design Rationale.
     

  9. Draw the class diagram to visually present the relationships among classes.

  10. Design the interface to each class.
  11. Write a complete class header.

    Write the signature for each method. The method signatures become the skeleton of your program.

    Code your class interface (not implementation) and document it as javadoc comments.

    Compile your class interface and remove any syntax errors.

    If you are a disciple of Test Driven Development you write your unit tests now.

  12. Draw a state diagram, if appropriate, to illustrate the time-dependent behaviour of a system.

  13. Draw sequence diagrams, as needed, to illustrate the dynamic properties of the system; the order in which objects are created and methods are invoked.

  14. Design and document the data structures to be used in the implementation using javadoc-style comments within the class.

  15. Design and document the algorithm for each non-trivial method using pseudocode or similar notation.


UML Class Relationships


Inheritance (IS-A)

Inheritance is a hierarchical relationship between a more general class (the superclass) and a more specialized class (the subclass). The subclass maintains the attributes and behavior of the superclass but may add additional attributes and behavior that specialize it. Every truck is a vehicle. Every savings account is a bank account.

Inheritance is implemented using the extends keyword. In UML, inheritance is denoted by a line with a triangle placed toward the superclass. Interface inheritance uses the implements keyword and has a dotted line.

Aggregation (HAS-A)

Aggregation is a one-way association relationship that implies ownership, wherein an object of one class consists of objects of another class. Think of aggregation as a Whole/Part relationship where the Part has its own life, independent of the Whole.

Aggregation is implemented using instance variables.

Every truck has a tire. (Truck is the whole, tire is the part).

class Truck extends Vehicle
{ ...
private Tire[ ] tires;
}
In UML, aggregation is denoted by a line with a diamond placed toward the aggregating class.

Composition, a strong form of aggregation, indicates that the components can't exist without the aggregate. The component can't belong to more than one aggregate. E.g., a window is composed of a slider (the slider can't exist without a window). The relationship is of a structural nature. In UML, composition looks like aggregation with a filled diamond.

Dependency (USES-A)

A class depends on another if one of its methods uses it in one of several ways: In UML, dependency is denoted by a dashed line with an open arrow that points to the dependent class.

Dependency indicates coupling.

Typical Implementation
class DependentClass
{
    ...
    void function1(ReferencedClass parameter1)
    ...
    ReferencedClass function2(...)  { ... }
    ...
    void function3(...)
    {
        ReferencedClass localvariable = new ReferencedClass();
        int x = ReferencedClass.staticMethod();
    }
}
 

Association

An association is a general relationship that describes two classes whose instances co-exist and play some role with each other.  For example, a man and a woman may co-exist in a marriage relationship.  An employee may work for a company.  One-way associations are aggregations (see above).
Two-way associations present the problem of keeping the information on both ends of the relationship consistent. For example, if Bill:Man is married to Sue:Woman, then each of these objects must refer to the other.  If the couple divorces and Bill remarries, both Sue and Bill must be updated. Usually we try to refine the design to avoid this, for example, by introducing a third class Marriage that aggregates both Man and Woman.

In UML, association is denoted by a solid line connecting two classes.

Typical Implementation
class Man
{
    Woman wife;
    ...
}
class Woman
{
    Man husband;
    ...
}


Example Problem

Draw a UML Class Diagram showing the relationships for these entities:

University
Faculty
Staff
Student
Constituent (people who comprise the University)
Professor
Lecturer
Scholar (someone who studies textbooks.)
Room
Classroom
Laboratory
Textbook
Desk

View Solution


CPE 308 Home