Skip to content

Inheritance Issues

Estimated time to read: 3 minutes

Overview

While inheritance is a powerful design tool that can help you create clean, reusable, and maintainable software systems. Misusing inheritance can lead to poor code.

Abusing and Misusing Inheritance

"Am I using inheritance to simply share attributes or behaviour without further adding anything special in my subclasses?"

If the answer is yes, then you're misusing inheritance. This is an indication of misuse, because there is no point for the subclasses to exists since the superclass already is enough.

Example Code

Pizza (Super) Class

public class Pizza {
 private List toppings;
 private String size;
 private String crustSize;

 public Pizza(String size, String crust){
  this.toppings = new ArrayList();
  this.size = size;
  this.crustStyle = crust;
 } 

 public void addTopping(String topping){
  this.toppings.add(topping);
 }
 public void bulkAddTopping(ArrayList toppingList){
  this.toppings.addAll(toppingList);
 }
 public void cook() throws InterruptedException {
  wait(10*6000);
 }
}

The pizza class has been generalised to know what toppings it will have, its size, style of crust, and how long it will take to cook. This seems reasonable, but let's look at why this is a misuse of inheritance by examining the code for a subclass of pizza.

Pepperoni Pizza (Sub) Class

public class Pepperoni extends Pizza {
 public Pepperoni(String size, String crust) {
  super(size, crust);
  super.addTopping("pepperoni");
 }
}

Despite the fact that a pepperoni pizza is a more specific kind of pizza, it is not really different from a superclass. You can see that the pepperoni constructor uses the pizza's constructor and adds toppings using the pizza's method. There's no reason to use inheritance in this case, because you can simply use only the pizza class to build the pizza with pepperoni as a topping.

Liskov Substitution Principle

The principle states that a subclass can replace a superclass, if and only if, the subclass does not change the functionality of the superclass.

A simple example; in an Animal class, we may have the methods Swim, Run and Walk. However, if we extended this class and created a Whale class, the Whale does not need the ability to Run or Walk.

The Liskov Substitution Principle is violated in this example because the Whale class overrides the Animal class' Running and Waking functions and replaces them with swimming behaviour.

Decomposition over Inheritance

If inheritance does not suit your need, consider whether decomposition is more appropriate. A smartphone is a good example of where decomposition works better than inheritance. A smartphone has characteristics of a phone and a camera. Here is one design.

Example of Inheritance without Decomposition

Screenshot 2022-07-14 at 21.08.21.png

It does not make sense for us to Inherit from the phone and then add camera methods to the subclass smartphone. We should be using decomposition to extract out the camera responsibilities, and put them in their own class.

Example of Inheritance with Decomposition

Screenshot 2022-07-14 at 21.09.16.png

The smartphone now indirectly provides the responsibilities of the camera in the phone. To separate part classes, the smartphone doesn't need to know how these classes work.