Refused Bequest — Code Smells Catalog Skip to content

Refused Bequest

Also known as: Refused Parent Bequest

Object Oriented Abusers Interfaces Code SmellDesign Smell Between Class

A Tower that extends Minion but throws NotImplemented on move(). The inheritance contract promises full support; the subclass delivers a runtime exception and an apology.

2 min read 1 source

Overview

Whenever a subclass inherits from a parent but only uses a subset of the implemented parent methods, that is called Refused Bequest. This behavior can happen both implicitly and explicitly:

  • Implicitly, when the inherited routine doesn not work
  • Explicitly, if an error is thrown instead of supporting the method

Whenever a child class is created, it should fully support all the data and methods that it inherits [1]. Fowler says that this smell is not that strong, though, and admits that he sometimes reuses only a bit of behavior, but it can cause confusion and problems [2].

However, there is one crucial thing. Both Fowler and Mäntylä are pointing out a strong case of this Code Smell whenever a subclass is reusing behavior but does not want to support the superclass interface [3] [1] [4].

Causation

This could happen due to bad development decisions when part of the needed functionality is already implemented in another class, but in general, the parent class is about something different from whatever the developer would like to implement in the new class. This inconsistency most likely indicates that the inheritance does not make sense, and the subclass is not an example of its parent. [5]

Problems

Liskov Substitution Principle Violation

The Liskov Substitution Principle describes that the relationship of subtypes and supertypes should ensure that any property proved about supertype object also holds for its subtype object.

🧪
Hard to Test

Each subclass might have different capabilities up and down the class hierarchies.

Example

Smelly
1class Minion(ABC):
2    @abstractmethod
3    def attack(self):
4        """ """
5
6    @abstractmethod
7    def move(self):
8        """ """
9
10class Tower(Minion):
11    def attack(self):
12        ...
13
14    def move(self):
15        raise NotImplementedException
PYTHON

Refactoring

  • Extract Subclass
  • Push Down Field
  • Push Down Method
  • Replace Inheritance with Delegation
  • Replace Superclass/Subclass with Delegate

Sources

Browse All 56 Smells