Object Relations:Composition
It took me a while before I could find a convincing real world example of composition. Thanks to civil engineering and Christopher Alexander; I got the enlightenment ;).
Yes it’s a
Building and the
Floors. The life time of a
Floor is totally dependent on the
Building. The
Floor is constructed, used and demolished through the
Building!
After finding the right example the next interesting challenge was, how to model the relation? Clearly Building and Floor are the two key objects in the problem and I designed them as separate public classes as follows.
public class Building {
private List floors;
……….
}
public class Floor {
private int level;
}
Functionally this model was fine and I was about to convince myself that the both Composition and Aggregation are same in the design and the difference is conceptual and existed only in the real world. However the lack of conceptual integrity in the model was bugging me for quite sometime before I realized that inner classes is the right way to go.
The following code (trivial) demonstrates how the lifetime of the Floor is tied to the building unlike in the previous model. Please excuse my coding conventions.
public class BuildingTest extends TestCase {
private static final int NO_OF_FLOORS = 5;
public void testFloorOrder(){
Building building = new Building(NO_OF_FLOORS);
Building.Floor previousFloor = null;
for(Building.Floor floor : building.Floors()){
if(null == previousFloor) {
previousFloor = floor;
continue;
}
Assert.assertEquals(true, previousFloor.isAtLowerLevelThan(floor));
previousFloor = floor;
}
}
}
public class Building {
private List<Floor> floors;
public Building(int numFloors) {
floors = new ArrayList<Floor>();
for (int level = 0; level < numFloors; level++)
floors.add(new Floor(level));
}
public int numberOfFloors() {
return floors.size();
}
public List<Floor> Floors() {
return floors;
}
public class Floor {
private int level;
private Floor(int level) {
this.level = level;
}
public boolean IsAtLowerLevelThan(Floor floor) {
return this.level <floor.level;
}
}
}