Refused Bequest

June 17, 2026 in code-smells 4 minutes

A intermediate-level guide to Refused Bequest: before-and-after java code and diagrams for a CS student.

The Burden of Unwanted Inheritance

Imagine you inherit a massive estate from a distant relative. Along with the house and land, you are legally handed a vintage car you have no interest in driving and a complex manufacturing business you have no desire to run. Even if you never touch the car or visit the factory, they are now part of your legal responsibility simply because you are the heir.

In software, inheritance can become this same kind of burden. When we use extends to gain access to some useful methods, we don’t just inherit the good parts; we inherit everything else too. If a subclass receives a method it cannot logically implement, it is forced to “refuse” that behavior.

class Device {
    public void powerOn() {}
    public void operate() {}
    public void recharge() { System.out.println("Recharging battery..."); }
}

class ManualClock extends Device {
    @Override
    public void recharge() {
        // Refused Bequest: Clocks don't need recharging
        throw new UnsupportedOperationException();
    }

    @Override
    public void operate() {
        System.out.println("Winding the clock manually.");
    }
}
  classDiagram
    Device <|-- ManualClock
    class Device {
        +powerOn()
        +operate()
        +recharge()
    }
    class ManualClock {
        +recharge()
        +operate()
    }

Identifying the Smell: Refused Bequest

Refused Bequest is a code smell that occurs when a subclass inherits methods from its parent but has no interest or ability to perform the actions those methods describe.

You can spot this in two ways:

  1. The Empty Override: You override a method with an empty body {} because the behavior is irrelevant to the subclass.
  2. The Exception Thrower: You override a method only to throw an UnsupportedOperationException. This is a loud, runtime way of saying, “I know I’m supposed to do this, but I refuse.”

While it might seem tempting to use inheritance just as a shortcut to grab some variables or helper methods from a parent class, this creates a fragile hierarchy. It violates the principle that a subclass should be a specialized version of its parent that can safely stand in for that parent anywhere in the code. If a piece of code expects a Device and calls recharge(), but receives a ManualClock that throws an exception, the program crashes. This break in the “behavioral contract” is the core problem.

  sequenceDiagram
    participant Client
    participant MC as ManualClock
    Client ->> MC: recharge()
    MC -->> Client: throw UnsupportedOperationException

Refactoring with Extract Class and Interfaces

To fix a Refused Bequest, we must stop trying to force an “is-a” relationship where it doesn’t fit. Instead of forcing every device into one giant hierarchy, we should use the Replace Inheritance with Composition approach or split responsibilities using interfaces. This follows the Interface Segregation Principle: clients should only be forced to depend on methods they actually use.

interface Operatable {
    void operate();
}

interface Rechargeable {
    void recharge();
}

class Device implements Operatable {
    @Override
    public void operate() { System.out.println("Operating device..."); }
}

class BatteryPoweredDevice extends Device implements Rechargeable {
    @Override
    public void recharge() { System.out.println("Recharging battery..."); }
}

class ManualClock implements Operatable {
    @Override
    public void operate() { System.out.println("Winding the clock manually."); }
}
  classDiagram
    Operatable <|.. Device
    Rechargeable <|.. BatteryPoweredDevice
    Device ..|> Operatable
    BatteryPoweredDevice --|> Device
    ManualClock ..|> Operatable

    class Operatable {
        +operate()
    }
    class Rechargeable {
        +recharge()
    }
    class Device {
        +operate()
    }
    class BatteryPoweredDevice {
        +operate()
        +recharge()
    }
    class ManualClock {
        +operate()
    }

By moving the specialized behaviors into distinct interfaces like Operatable and Rechargeable, we allow classes to pick and choose exactly what they are capable of doing. A ManualClock is now just an Operatable object; it no longer carries the heavy, unnecessary baggage of a charging requirement.

When to Use It, and When Not To

Refactoring toward composition and smaller interfaces is almost always the right move when your hierarchy feels “bloated.” If you see subclasses throwing exceptions for parent methods, you have already passed the point where simple inheritance is sufficient.

However, don’t over-engineer everything into tiny fragments immediately. Inheritance is still highly effective when there is a strict, undeniable “is-a” relationship (e.g., a Dog is an Animal). If the hierarchy is shallow and every subclass truly needs every method of the parent, adding extra layers of interfaces might add unnecessary complexity to your system.

Takeaways

  • Inheritance must represent a true “is-a” relationship where the subclass can fulfill all parental promises.
  • Throwing UnsupportedOperationException in an overridden method is a major red flag for Refused Bequest.
  • Use “Extract Class” or interfaces to provide narrower, more specific responsibilities to your objects.
  • Favor composition and interface implementation over deep, bloated inheritance trees.

Usage

Polymorphic use of rechargeable behavior

Device d = new BatteryPoweredDevice();
d.recharge(); // Works as expected

The danger of the Refused Bequest

// This would cause a runtime error in the 'before' version
Device clock = new ManualClock();
try {
    clock.recharge();
} catch (UnsupportedOperationException e) {
    System.out.println("Error: Clock cannot be recharged!");
}