Composition in Flutter

Composition in Flutter

Flutter heavily favours composition over inheritance, or so they say. In this blog, we will look at what these concepts(Inheritance and Composition) are and how they are being used in Flutter.

What is Inheritance

Inheritance is an OOP mechanism where one class, a subclass, is derived from another class, a superclass. The subclass inherits all the properties and methods of a superclass.

Polymorphism is the mechanism by which the subclass implements the inherited behaviour to match its specific type. In the example below Fish() inherits from Animal(), hence a subclass of Animal(). Fish() overrides move() method to match its behaviour, i.e. fish swims.

What is composition?

Composition is a way to combine simple objects to create complex ones. For instance, when making a computer you put together motherboard, CPU, GPU, RAM, and a hard drive. This is composition.

In programming, composition is where a class has properties which themselves are instances of other classes. Using our computer example, our code would look like the example below.

A Computer is composed of CPU and RAM.

Inheritance and polymorphism expand behaviour of a class through the hierarchy where the subclass inherits the behaviour of its superclass and implements the inherited behaviour to match its specific type.

In Composition, on the other hand, a class contains instances of other classes which bring their own properties and behaviour to the containing class. From the Computer example above, the overall speed of the Computer is determined by the clock speed of the CPU.

Flutter uses composition in building widgets, i.e., widgets are composed of other widgets. These widgets make the app UI.

The following is an example using composition to compose BusinessCardWidget widget.

BusinessCardWidget is composed of CircleAvatar, Column, Row, and Text widgets.

Looking at the code, BusinessCardWidget is a subclass of Stateless widget. The class overrides build() method. This is an example of how inheritance is used in Flutter.

Composition brings flexibility in building Flutter UI. You put together any number of widgets to achieve the desired UI in your app.

Below is an illustration of how to build a checkbox in Flutter, using composition. The goal is to create checkboxes that will look like ones in the diagram below.

Screenshot 2020-09-05 at 14.56.10.png

Reading through flutter documentation, CheckboxTile looks like what we are looking for. However, CheckBoxListTile comes with padding which we would not like to have in our app.

To achieve our goal we are going to build a custom widget called LabelledCheckBox.

When you look at the desired widget you will notice that there are two widgets, a CheckBox and a Text, stacked horizontally. With this knowledge, we can start building our custom widget.

LabelledCheckBox inherits from StatelessWidget and overrides the build() method to return a Row. Row displays its children in a horizontal array. Inside the Row, we will then put Checkbox and Text widgets.

Then, we will wrap the Row in a InkWell widget. InkWell is a rectangular area of a Material that responds to touch.

The code below shows the full implementation of `LabelledCheckBox.

The LabelledCheckBox widget is composed of InkWell, Row, CheckBox and Text widgets.

Once we are done creating the custom widget we can use it anywhere in our app like below.

Unix philosophy: Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface.

In composition, a component does just one thing and does it well. Using our Computer example, the CPU class will describe characteristics of a CPU for example clock speed and tasks performed by the CPU, only.

This also applies for widgets in Flutter. For example, a Column will be used to display widgets vertically. Padding widget provides different ways of applying padding to other widgets.

Prefer composition over inheritance as it is easier to modify later.

In composition, you can replace components of a class with one that best suit your need. Remember the LabelledCheckBoxwe built above. We can replace the CheckBox with a RadioButton. Hence the flexibility.

Composition also offers test-ability of a class where the dependencies, i.e. the contained classes can be mocked.

However, when misused, composition can result in ugly code such as nested hell, like in the code below.

To fix the issues in the code above you can extract the Card widget to a new method as in the code below.

.

The method has a return type of Widget. It returns Card which is a Widget. It could also have a return type of Card if you would like to have a more specialized return type.

Once you have the method above you could use it to in widget we previously had like in the code below.

This way we are able to reuse buildCard() method.

That said, do not use a compose-always approach. Compostion is a has a relationship. For example, A computer has a CPU, A car has an engine etc.

Inheritance is a is a relationship. For example, A fish is an Animal.

Prefer composition for a has a relationship and inheritance for a is a relationship.

Happy coding!