September 2003 Technical Tip Composition or Aggregation?

If you've done any object oriented programming or modeling, then you're probably familiar with composition and inheritance. But do you really understand composition? You may know composition as the means by which a "has a" relationship is implemented. But when is a "has a" relationship composition, and when is that relationship aggregation? The difference is subtle but significant!

First, let's give ourselves a basis for discussion. Consider the Student class a very simple class which encapsulates a student's name and grade. (View source here) The UML class diagram for the Student class appears below. (In the UML a plus sign indicates a public field or method, a hyphen indicates private, and a pound sign indicates protected.)

Now we will create a StudentAthlete class. If we view the class as "having" a Student, then composition would be appropriate. In composition, we use an instance of another class (rather than a primitive) as an instance variable. This is really nothing new as we use composition all the time when we use a String as an instance variable, for String is, afterall, a class. Our StudentAthlete class will consist of a Student and an array of String indicating the Student's sports. (View source here)

But is this relationship one of composition or aggregation? Formally, we are using aggregation rather than composition. Composition is a stronger relationship than aggregation. In composition, (1) the part object may belong to only one whole, and (2) the parts are usually expected to live and die with the whole (that is, deletes are cascading.) In the UML a white diamond indicates aggregation whereas a black diamond indicates composition.

So how does it impact our coding? The affect is usually limited to the constructor definition or how it is invoked. The table below illustrates this point.

Test Application
(View source here)

StudentAthlete
(View source here)

Comment

Student s = new
  Student(Noah, 11);

StudentAthlete sa = new
  StudentAthlete(s,
  new String [ ] {
    "Football",
    "Wrestling",
    "Track" } );
// constructor
public StudentAthlete(
  Student student,
  String[ ] sport )
{
   this.student = student;
   this.sport = sport;
}

Aggregation: Student s exists independent of StudentAthlete sa. Changes to s will effect sa.student, and vice versa. Indeed, there is only one instance of a Student.

Student s = new
  Student(Noah, 11);

StudentAthlete sa = new
  StudentAthlete(s,
  new String [ ] {
    "Football",
    "Wrestling",
    "Track" } );
// constructor
public StudentAthlete(
  Student student,
  String[ ] sport)
{
   this.student = 
     new Student(
      student.getName(),
      student.getGrade() );
   this.sport = sport;
}

I'd call this a hybrid! There are two identical but distinct instances of Student. Changes to one will not affect the other. This can result in integrity problems.

StudentAthlete sa = new
  StudentAthlete(
    new Student("Noah", 11),
    new String [ ] {
      "Football",
      "Wrestling",
      "Track"} );

(either of the above)

Composition: Student exists within StudentAthlete only.

The following diagram (non-UML) shows the aggregation relationship discussed in the first row of the table.


Go to the articles index. Written by Bill Qualls. Copyright © 2003 by Caliber Data Training 800.938.1222