Lesson 9
No Object is an Island
Chapter 2: Object interaction
Aggregation and composition
In the previous exercise, Car and Driver are quite loosely dependent. A Driver instance will only have access to a Car in the drive() method (passed as an input argument).
But perhaps we might also want Driver to actually have some ownership towards the Car instance? Since he will be driving the car a lot?
In object-oriented programming, such “has-a” relationships are known as aggregation or composition. Some people also call this a “whole/part” relationship. So you can think of an object as being “part of” another object.
For example, your Hero might have a Hand and a Weapon, a Book might have an Author, a Car might have an Engine and a Wheel, a Webpage might have a Button and a SearchBar etc.
Naturally, the object ‘part’ will be an instance attribute/variable of the ‘whole’ object, so you would usually initialise them in the constructor of the ‘whole’ object.
There are two ways to implement composition/aggregation. You can pass in an existing instance as an input argument to the constructor (weapon in the code below), or you can construct a new object directly inside the constructor (Head() in the code below).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | |
Unlike previously with enemy, I used the .is_charged() method of self.weapon in Line 14 without passing it as an input argument to cast_spell(), since Hero actually owns a weapon. In a sense, you can consider aggregation/composition to be stronger form of dependency compared to just passing the object as an input argument to a method. Think of your hero owning a weapon vs. picking up a weapon when needed.
A Head instance itself can also have more ‘parts’ (Eye, Nose, Mouth), and each can have their own ‘parts’ (an Eye might have an Eyebrow, Pupil, Iris etc. So you end up with a hierarchy of ‘parts’!
As you can see, composition/aggregation can be quite a powerful abstraction!