Android Tutorial: Inheritance applied with practical examples

Michael Ganchas
The Startup
Published in
5 min readNov 1, 2020
Image from https://www.manypixels.co/gallery/

Hi all!

Today I’d like to share with you some examples of different types of OOP (Object-Oriented Programming) inheritance and where each might be useful to use.

Details

When talking about inheritance, I like to separate between what I call Structure inheritance (SI) from Functionality inheritance (FI). The first one, as the name suggests, is to what family (structure) a type belongs to, whereas the latter relates to what sort of abilities (functionalities) a type needs to have.

There are several types of inheritance, but we’re going to focus on the ones I find more useful:

  • Single inheritance — (SI)
  • Multilevel inheritance — (SI)
  • Single “Base controller” inheritance — (FI)
  • Abstract “Base controller” inheritance — (FI)
  • “Behavior contract” inheritance — (FI)
  • Capacities/Composition inheritance — (FI)

We’re going to use Java for this tutorial.

Single inheritance

Let’s suppose a typical scenario where we have an app that saves data on a server and persists that data on the device (e.g. to save network calls for sorting operations). It’s standard to map that data into data model types.

Since we have both server and local (persistent) data, they might be using different storing structures. Let’s assume we have a document-oriented database in our server and a relational database locally.

It’s natural to assume that each mapped model will have (at least) the following data available:

So, each entity that mapped will extend (inherit from) BaseEntity. Let’s consider the following UserEntity type has an example of that:

This brings us some advantages:

  • Easier shared model data management
  • Less code duplication
  • Segregation of user attributes from shared ones

Following on that, it’s useful to then create some DAOs to access each of those repositories (server and local). A possible implementation for a local UserDAO might look like the following:

Note: Read more about the singleton pattern and final classes.

When receiving the result from the “getUser” method, we can opt to use either the full model (UserEntity + BaseEntity) or just the shared model (BaseEntity).

Multilevel inheritance

Following on the previous structure, let’s assume we have a job listing app, where each user needs to have the data of UserEntity, plus some area-specific attributes.

On that app, there’s an area for Tech profiles and another one for Construction profiles. A possible implementation for both could be:

UserTechEntity
UserConstructionEntity

Note: Read more about QuickSort and Dijkstra’s algorithm.

Like in the Single inheritance, we can then segregate what level of entity we’d like to consider for each of these types (UserXXXEntity, UserEntity, or BaseEntity).

Single “Base controller” inheritance

In mobile development, this is one that I’ve used constantly. It’s useful to use in controllers (activities or fragments), when we want to centralize a certain behavior that fits into one of the following requirements:

  • Mandatory invocation in every of its children controllers
  • Easy access to a shared functionality between them where its running moment and responsibility makes sense to be in the base type

Let’s assume that for our job listing app we’d want to do add a user registration flow, while also needing to make it so that every controller in it, except for the registration one, checks for location permission for our app.

Here, we can see that every controller should check for a user’s registration status, to possibly redirect him/her to the registration flow if not already registered. Also, we need to validate, request (if not allowed) and handle the user’s response to our location permission requirement.

Here’s a possible implementation for that base controller:

Note: The checkForLocationPermission method is protected to ensure that it is only known and accessible to its children controllers.

As for a child controller example, it could be something like this:

As a side note, I’m currently using this same logic in my MapCrumbs app and it works like a charm for me.

Abstract “Base controller” inheritance

This one is very similar to the last one in what it provides as mandatory validations and also as a centralized component for what would otherwise be code duplication for handling the same requirement; the difference here is that it orders every child to say how they behave in certain areas. It uses abstract methods to enforce that.

In the same job listing app, let’s suppose each controller was required to expose a method to reset all its member variables’ values. For that, the BaseActivity would look like:

Note: The abstract keyword now needs to be added to the class’ signature.

Generally speaking, there are some cases where this approach might come in handy. If for example there’s some component that, abstractly, knows that it is dealing with a child of BaseActivity (without knowing which one), and needs to invoke this method, then this pattern can be seen as a resourceful way of achieving that. A possible implementation could be:

“Behavior contract” inheritance

This one uses the idea that a controller’s core behavior is bound to its business logic. What I mean by this is that we could envision core functionalities for all our controllers to have to implement.

Let’s take our example job listing app, in which we want some controllers to fit in flow-like steps (A comes before B, B comes before C), and that every one of them has certain functionalities related to flow.

A possible contract for that could look like:

Here, we’re saying that every controller implementing this should know how to handle a go-back operation, to be able to go forward and a flow escape method. According to what step the user’s in, they could be very different:

  • On the first page, the goBack and exitFlow could be exactly the same
  • To move forward, only the current controller knows where to go to
  • Invoking the exitFlow after the first page could prompt a dialog stating that all data will be lost and asking for confirmation

There are many scenarios where this fits and I’ve recently used it professionally to implement flow-like steps and where I needed this sort of contract to be applied.

Capacities/Composition inheritance

Last but surely not least, the method that inspired the phrase most of us have heard in our career:

Use composition over inheritance

It tells us that instead of using single (or multiple) base type inheritance, we should structure our components according to what they can atomically do.

A good analogy for is thinking about a parent-child relationship: if that child would inherit from its parent’s base type, it would mean that by age 2 he/she should be able to drive, since its exposing such a functionality (method), which is highly unlikely true.

Using the approach of composition, we’d be able to expose atomic functionalities as it made sense for that component (at 18 adding the canDrive method).

For our job listing app, we could add functionalities such as showing video/banner ads or to show a loading dialog to some of our controllers. Let’s see how we could achieve that.

I would like to point out that these methods, designs and patterns or not one size fits all, and that each may (or not) be adequate according to what challenge we have in front of us.

That’s it for today. Feel free to ask any questions or add suggestions if you’d like!

Cheers!

--

--