Object Composition

../_images/composition.png

Objects can be attributes of other objects.

You can use this mechanism to represent relationships between objects. For instance you could model one-to-one, one-to-many or many-to-many relationships. This has some similarity to database design, but with classes you have more options.

Object Composition is something you use in Python all the time, e.g. when you have a list of integers and refer to the first item of the list, you are accessing an int object inside a list object.

Many of the principles of good OOP manifest in the statement “Prefer composition over inheritance”. Here are two examples:

Example 1: Galaxy

Imagine you want to have a Galaxy class that represents many planets.

A very bad design would be:

Galaxy is a subclass of Planet

This violates Liskovs Substitution Principle. A galaxy is not a special type of planet!

A better design solution would be:

A Galaxy contains many Planets

An implementation could look like this:

class Galaxy:

    def __init__(self):
        self.planets = {}

    def add_planet(self, planet):
        self.planets[planet.name] = planet


alpha_quadrant = Galaxy()
pandalor = Planet(name="Pandalor", description="home of the pandas")
alpha_quadrant.add_planet(pandalor)
alpha_quadrant.add_planet(Planet(
    name="Sirius",
    description="they are doing very serious business here",
))

Example 2: Composite Pattern

In this exaple, Node objects contain other Node objects and Leaf objects to construct a tree. The traverse() method walks across all nodes in the tree.

class Node:

    def __init__(self, *args):
        self.subnodes = args

    def traverse(self):
        result = []
        for n in self.subnodes:
            result += n.traverse()
        return result


class Leaf:

    def __init__(self, name):
        self.value = name

    def traverse(self):
        return [self.value]


my_tree = Node(
            Node(
                Node(
                    Leaf('gorilla'),
                    Node(
                        Leaf('chimp'), Leaf('human')
                        )
                    ),
                Node(
                    Leaf('cat'),Leaf('dog')
                    ),
                ),
            Node(
                Node(
                    Leaf('chicken'),
                    Node(
                        Leaf('lizard'),Leaf('turtle')
                        ),
                    ),
                Node(
                    Leaf('shark')
                    ),
                )
            )

print(my_tree.traverse())

Hint

Modeling classes using Object Composition is one of the most important techniques in Object-Oriented-Programming. Look up the terms Object-Oriented-Design and Design Patterns for further reading.