Replace Superclass with Delegate

Compare
Symptom
Human

A subclass that inherits from a parent that doesn't quite fit — overriding methods to no-ops, throwing 'unsupported', or using only some of the parent's surface (refused-bequest pattern).

Agent

A subclass that overrides parent methods to no-ops or 'unsupported'; the agent reasoning about polymorphic calls on parent-typed references cannot trust the contract.

Goal
Human

Inheritance from a superclass that doesn't really fit (Liskov violations, awkward methods) becomes composition: the former subclass holds an instance and delegates explicitly.

Agent

The former subclass holds a delegate of the former parent's role; the agent reads the new class's interface as the contract instead of loading the former parent to filter out methods the subclass refused.

Before the refactoring

class CategoryItem extends Scroll {
// uses some Scroll methods, refuses others
}

After the refactoring

class CategoryItem {
constructor() { this.scroll = new Scroll(); }
date() { return this.scroll.date(); }
}
Example source: Illustrative example written for this site, not a quotation from any source.
Pressure
Human

Liskov violations: consumers can't trust subclass instances; polymorphism becomes unsafe; the inheritance relationship misleads readers about what the subclass actually is.

Agent

Liskov violations break the agent's polymorphic reasoning; the agent must defensively check at every call site whether the subclass honors the parent's contract.

Tradeoff
Human

Adds a forwarding method on the former subclass for every method the old superclass exposed — only worth it when the superclass relationship is misleading.

Agent

Composition adds a forwarding method on the former subclass for every parent method exposed; the agent loses syntactic polymorphism and pays ceremony for explicit delegation.

Relief
Human

The misleading is-a relationship disappears; the former subclass can change its delegate's class without affecting its callers.

Agent

References typed against the former subclass hold only the methods the class actually implements; generated code that calls a method on a reference no longer dispatches through inherited methods the subclass overrode to no-op or unsupported.

Trap
Human

Replacing every inheritance with composition — including ones where the Liskov contract genuinely holds — pays forwarding-method ceremony for no real fit improvement.

Agent

Replacing inheritance with delegation on hierarchies where the subclass uses every inherited method adds a forwarding method per parent method without changing what the agent's generated calls do.