Refused Bequest
Description (What)
A class that implements an interface but doesn't use all of its methods, there is a discrepency between the interface and class. This can apply to any hierarchy.
How to Locate It (Where)
Look at two or more sub-classes that implement the same interface but either override different sets of methods or implement different subsets of methods.
How It Manifests (Why)
This can occur when the basis of the existence of the interface is logically flawed. Any class that implements an interface must be logically coherent to the interface and must strictly implement all its methods.
It can also occur when a programmer tries to simply their codebase by merging two or more similar looking classes under a single interface.
How to Fix It (Possible Treatments)
In Example 1, Extract Superclass is used. This treatment identifies the truly common methods implemented by the sub-classes and keeps only those in the superclass and simplifies the interface. This can have the effect of broadening the scope of the interface.
In Example 2, Extract Superclass is also used for the roughly same reasons.
Other treatments are also possible based on the specific scenario, they can be found here
Examples
Example 1
Before:
Car and Bicycle both implement the interface Vehicle since they share common methods and logical attributes. However some of the methods of the interface only apply to the Car and not Bicycle and so the Bicycle is not able to fulfill some duties of Vehicle correctly since they do not apply to it.
Observed Code Smells:
- Refused Bequest (lines 93-101)
After:
Applied Extract Superclass and removed the non-common functions from the interface Vehicle. Created a new interface that extends the old interface.
Refactoring Applied:
- Refused Bequest
- Extract Superclass(refuel() and replaceEngine() from Vehicle interface)
Observed Code Smells After Refactoring:
- None
Example 2
Before:
The class LegoPart that related to toys,
intends to use the dimension getter method only from class BuildingBrick for construction,
Some more fields and methods in class BuildingBrick are not applicable to class LegoPart.
The inheritance relationship is embarrassing.
Observed Code Smells:
- Refused Bequest (line 44-108)
After:
Applied Extract Superclass method to consolidate the common dimension methods in to a
common superclass Block and then have class BuildingBlock and class LegoPart to extends it with
their own features.
Refactoring Applied:
- Refused Bequest:
- Extract Superclass (line 12-45)
Observed Code Smells After Refactoring:
- None
When to Ignore
None
More
- Example 1
- Example 2
- Before
- After
001 interface Vehicle {002 public void forward();003004 public void reverse();005006 public void turn(String direction);007008 public void refuel();009010 public void replaceEngine(String newEngine);011 }012013 class Car implements Vehicle {014 private int fuelPercentage;015 private int distanceTravelled;016 private String direction;017 private String engine;018019 public Car(String engine) {020 this.fuelPercentage = 100;021 this.distanceTravelled = 0;022 this.direction = "Forward";023 this.engine = engine;024 }025026 @Override027 public void forward() {028 this.distanceTravelled += 10;029 this.fuelPercentage -= 1;030 System.out.println("New distance travelled: " + this.distanceTravelled);031 System.out.println("Current fuel percentage: " + this.fuelPercentage);032 }033034 @Override035 public void reverse() {036 this.distanceTravelled -= 10;037 this.fuelPercentage -= 1;038 System.out.println("New distance travelled: " + this.distanceTravelled);039 System.out.println("Current fuel percentage: " + this.fuelPercentage);040 }041042 @Override043 public void turn(String direction) {044 this.direction = direction;045 System.out.println("New direction: " + this.direction);046 }047048 @Override049 public void refuel() {050 if (this.fuelPercentage == 100) {051 System.out.println("Fuel is full");052 } else {053 this.fuelPercentage = 100;054 }055 }056057 @Override058 public void replaceEngine(String newEngine) {059 this.engine = newEngine;060 System.out.println("New engine: " + this.engine);061 }062063 }064065 class Bicycle implements Vehicle {066067 private int distanceTravelled;068 private String direction;069070 public Bicycle() {071 this.distanceTravelled = 0;072 this.direction = "Forward";073 }074075 @Override076 public void forward() {077 this.distanceTravelled += 10;078 System.out.println("New distance travelled: " + this.distanceTravelled);079 }080081 @Override082 public void reverse() {083 this.distanceTravelled -= 10;084 System.out.println("New distance travelled: " + this.distanceTravelled);085 }086087 @Override088 public void turn(String direction) {089 this.direction = direction;090 System.out.println("New direction: " + this.direction);091 }092093 @Override094 public void refuel() {095 throw new UnsupportedOperationException("Bicycle does not support refueling");096 }097098 @Override099 public void replaceEngine(String newEngine) {100 throw new UnsupportedOperationException("Bicycle does not support an engine");101 }102 }103104 public class RBBE1 {105106 public static void main(String[] args) {107 Vehicle car = new Car("V6");108 Vehicle cycle = new Bicycle();109 car.forward();110 car.forward();111 car.forward();112 car.refuel();113 cycle.forward();114 cycle.forward();115 cycle.forward();116 cycle.refuel();117 }118119 }120