Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

Composition over inheritance

After this lesson: I can choose composition over inheritance and say why.

55 min lesson4 commandsEveryday Linux commands lab: the thirty commands engineers type from memory

Composition builds an object from parts

Composition means building an object out of other objects, so it has parts instead of being a kind of something. Many designers prefer composition over inheritance, because parts can be swapped while the program runs. A report that holds a style object can change its look without a new class.

By the end of this lesson

Note

I can choose composition over inheritance and say why.

Key words

WordWhat it means
Compositionbuilding an object from other objects
Is-athe link between a subclass and its parent
Has-athe link between an object and its parts
Delegationpassing a job on to a part
Componentan object used as a part of another

The cells students fill in are left blank in this preview.

Is-a and has-a are different links

A DiskCheck is a Check, so inheritance fits. A car has an engine. It is not a kind of engine. When one object has another as a part, you do not inherit. You store the part in an attribute and call it.

This is composition. When the object passes a job on to the part, that is delegation.

Two interchangeable style parts

Code: python
class Plain:
    def line(self, label, value):
        return label + ": " + str(value)

class Table:
    def line(self, label, value):
        return label + " | " + str(value)

A Report that has a style

Code: python
class Report:
    def __init__(self, style):
        self.style = style
        self.rows = []

    def add(self, label, value):
        self.rows.append([label, value])

    def set_style(self, style):
        self.style = style

    def render(self):
        lines = []
        for row in self.rows:
            lines.append(self.style.line(row[0], row[1]))
        return lines

Make a folder for this lesson

Command
mkdir -p ~/oop3

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Go into it

Command
cd ~/oop3

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the classes to report.py

Command
printf 'class Plain:\n    def line(self, label, value):\n        return label + ": " + str(value)\n\nclass Table:\n    def line(self, label, value):\n        return label + " | " + str(value)\n\nclass Report:\n    def __init__(self, style):\n        self.style = style\n        self.rows = []\n\n    def add(self, label, value):\n        self.rows.append([label, value])\n\n    def set_style(self, style):\n        self.style = style\n\n    def render(self):\n        lines = []\n        for row in self.rows:\n            lines.append(self.style.line(row[0], row[1]))\n        return lines\n' > report.py

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

A part can be swapped while running

The report does not format anything. It asks self.style.line(...) to do it. Any object with a line method will work.

set_style swaps the part. The same report, holding the same rows, now looks different. With inheritance the look would be fixed when the object was made.

Swap the style and show the report again

Command
python3 -c "from report import Report, Plain, Table; r = Report(Plain()); r.add('cpu', 40); r.add('disk', 71); print(r.render()); r.set_style(Table()); print(r.render())"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Inheritance grows a class for every mix

Suppose reports can use two styles and send to two places. With inheritance you write a class for every mix: plain to screen, plain to file, table to screen, table to file.

With composition you write two style classes and two place classes, and a report holds one of each. Every extra option adds one class, not a whole new row.

Worked example: classes needed

StylesPlacesInheritanceComposition
224 classes4 classes
339 classes6 classes
4520 classes9 classes

The cells students fill in are left blank in this preview.

A common mistake

Warning

Many people think composition just means more code, so inheritance is always shorter. For two classes it can be. But inheritance fixes the behaviour when the object is made and grows with every mix. Use is-a only when it is plainly true, and has-a otherwise.

About this lab and its source: Everyday Linux commands lab: the thirty commands engineers type from memory

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.