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

More about Refused Bequest

001  interface Vehicle {
002   public void forward();
003  
004   public void reverse();
005  
006   public void turn(String direction);
007  
008   public void refuel();
009  
010   public void replaceEngine(String newEngine);
011  }
012  
013  class Car implements Vehicle {
014   private int fuelPercentage;
015   private int distanceTravelled;
016   private String direction;
017   private String engine;
018  
019   public Car(String engine) {
020   this.fuelPercentage = 100;
021   this.distanceTravelled = 0;
022   this.direction = "Forward";
023   this.engine = engine;
024   }
025  
026   @Override
027   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   }
033  
034   @Override
035   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   }
041  
042   @Override
043   public void turn(String direction) {
044   this.direction = direction;
045   System.out.println("New direction: " + this.direction);
046   }
047  
048   @Override
049   public void refuel() {
050   if (this.fuelPercentage == 100) {
051   System.out.println("Fuel is full");
052   } else {
053   this.fuelPercentage = 100;
054   }
055   }
056  
057   @Override
058   public void replaceEngine(String newEngine) {
059   this.engine = newEngine;
060   System.out.println("New engine: " + this.engine);
061   }
062  
063  }
064  
065  class Bicycle implements Vehicle {
066  
067   private int distanceTravelled;
068   private String direction;
069  
070   public Bicycle() {
071   this.distanceTravelled = 0;
072   this.direction = "Forward";
073   }
074  
075   @Override
076   public void forward() {
077   this.distanceTravelled += 10;
078   System.out.println("New distance travelled: " + this.distanceTravelled);
079   }
080  
081   @Override
082   public void reverse() {
083   this.distanceTravelled -= 10;
084   System.out.println("New distance travelled: " + this.distanceTravelled);
085   }
086  
087   @Override
088   public void turn(String direction) {
089   this.direction = direction;
090   System.out.println("New direction: " + this.direction);
091   }
092  
093   @Override
094   public void refuel() {
095   throw new UnsupportedOperationException("Bicycle does not support refueling");
096   }
097  
098   @Override
099   public void replaceEngine(String newEngine) {
100   throw new UnsupportedOperationException("Bicycle does not support an engine");
101   }
102  }
103  
104  public class RBBE1 {
105  
106   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   }
118  
119  }
120