Refused Bequest - A Code Smell

Introduction

Refused Bequest is kind of a code smell. It is based on the LISKOV Substitution Principle because it violates this principle. The contract of the base class is not honored by the derived class, and that forms this code smell. Martin Fowler has mentioned about this code smell in his book Improving the Design of Existing Code by saying,
 
"Sub-classes get to inherit the methods and data of their parents. But, what if they don't want or need what they are given? They are given all these great gifts and pick just a few to play with".
 
There is a child class and it inherits from a base class, but the child class doesn't need all behavior provided by the base class. Other behaviors which are not required to child class are refused. That refused behavior is class refused bequest.
 
Let me explain with one example.
 
A base class for the Base Tax calculation.
  1. public class Tax {  
  2.   
  3.     protected double CalculateBaseTax()   
  4.     {  
  5.      }  
  6.   
  7.     protected double AddTax(double tax) {  
  8.   
  9.      }  
  10.   
  11.     public virtual double GetTaxAmount() {  
  12.         double tax = CalculateBaseTax();  
  13.         var taxAmount =  AddTax(tax);  
  14.         return taxAmount;  
  15.     }  
  16. }  
A derived class for the total Tax Calculation, 
  1. public class Person: Tax  
  2. {  
  3.       
  4.     private double CalculateTax()   
  5.     {  
  6.     }  
  7.   
  8.     public override double GetTaxAmmount() {  
  9.         double tax = CalculateTax();  
  10.         var taxAmount = AddTax(tax);  
  11.   
  12.        return taxAmount;  
  13.     }  
  14. }  
In the above example, the base class, Tax, has virtual method "GetTaxAmount" and it is overridden by Tax class Person. But, overridden method of Person class is not giving respect to the virtual method of Tax class. Person's class virtual method has totally new implementation. It is refusing the implementation of parent class method. So, it is a kind of code smell in the form of Refused Bequest. 
 
In the case of method, Refused Bequest is similar to no-op (NOP) except there is one difference. A no-op is an overridden method in a sub-class that purposefully removes all behavior of virtual method of base class into itself, but Refused Bequest disregards only few behavior.

Ways to solve the issue of Refused Bequest

Refused bequest code smell can be solved by using two methods.
  • Push down method and push down field
  • Replace Inheritance with Delegation

Push Down Method and Push Down Field

It is a common way to solve the issue of Refused Bequest.  Remove the method or property from Base class and move it to that subclass where it fits.
 
Example
 
Code with Refused Bequest.
  1. public class Vehicle  
  2.    {  
  3.        protected void Drive() { }  
  4.    }  
  5.   
  6.    public class Car : Vehicle  
  7.    {  
  8.    }  
  9.   
  10.    public class Plane : Vehicle  
  11.    {  
  12.    }  
Code solving the problem of Refused Bequest.
  1. public class Vehicle  
  2. {  
  3. }  
  4.   
  5. public class Car : Vehicle  
  6.    void Drive() { }  
  7. }  
  8.   
  9. public class Plane : Vehicle  
  10. {  
  11. }  

Replace Inheritance with Delegation

The child class copies or exposes the API of parent class by using "Inheritance". So, the unwanted properties or methods also get copied. Delegation eliminates the copying of the whole API from Parent class. It provides a way to copy only required functionality from the parent class.
 
Example

I want to create Stack from List. It means, I want to use some features of List like add, remove, and top item by changing its behavior according to Stack. If I use inheritance, then it will inherit all other behaviors of List that is not required for Stack. Thus, it will create the issue of Refused Bequest. So, this can be solved by using Delegation.
 
Code with Delegation.
  1. public class CustomStack  
  2.     {  
  3.         private readonly List<string> _list = new List<string>();  
  4.   
  5.         public List<string> Push(string item)  
  6.         {  
  7.             _list.Insert(0, item);  
  8.             return _list;  
  9.         }  
  10.   
  11.         public List<string> Pop()  
  12.         {  
  13.             if (!_list.Any()) return null;  
  14.   
  15.             _list.RemoveAt(0);  
  16.             return _list;   
  17.         }  
  18.   
  19.         public string Peek()  
  20.         {  
  21.             return _list.Any() ? _list[0] : null;  
  22.         }  
  23.     }  

Conclusion

Refused Bequest is a kind of a design smell. It should be eliminated during the design of classes. There are two major ways -- Push down method and replace inheritance with delegation are very good approaches to refactor the code that contains Refused Bequest code smell symptom.


Similar Articles