# Replace Inheritance with Delegation

> Turn a subclass that uses only part of its superclass into a class that holds an instance of it and forwards just the calls it needs.

- kind: technique
- category: dealing-with-generalization
- aliases: Replace Superclass with Delegate, Replace Subclass with Delegate
- canonical: https://aipatterns.dev/refactoring/techniques/replace-inheritance-with-delegation
- inspired-by: https://refactoring.guru/replace-inheritance-with-delegation

## Problem

A class extends another to reuse some of its code, but it is not truly a kind of that class. It inherits methods that make no sense for it, and callers can use them to break its rules.

## Solution

**Give the class a field holding an instance of the former superclass, forward the calls you actually need to it, and remove the `extends`.**

## Before

```ts
class AuditLog extends Array<AuditEntry> {
  record(actorId: string, action: string, target: string): void {
    this.push({ actorId, action, target, at: new Date() });
  }

  byActor(actorId: string): AuditEntry[] {
    return this.filter((e) => e.actorId === actorId);
  }
}

const log = new AuditLog();
log.record("u-7", "role.grant", "u-12");
log.splice(0, 1); // compiles: entries can be erased from an append-only log
```

## After

```ts
class AuditLog {
  private readonly entries: AuditEntry[] = [];

  record(actorId: string, action: string, target: string): void {
    this.entries.push({ actorId, action, target, at: new Date() });
  }

  byActor(actorId: string): AuditEntry[] {
    return this.entries.filter((e) => e.actorId === actorId);
  }

  get size(): number {
    return this.entries.length;
  }
}

const log = new AuditLog();
log.record("u-7", "role.grant", "u-12");
// log.splice(...) no longer exists
```

## Why

- The class exposes only operations that keep its invariants: append-only stays append-only.
- Changes to the former superclass no longer leak into the public API.
- You can swap the delegate for another implementation, such as a database-backed store.

## Steps

1. Add a field of the superclass type to the subclass, initialized to `this`. Run the tests.
2. Change each method in the subclass that uses inherited members to call them through the field. Run the tests.
3. List the inherited methods callers actually use. Add a forwarding method for each one that should stay public.
4. Remove the `extends` clause and initialize the field with a new instance of the former superclass. Run the compiler and tests.
5. Fix callers that used the class as the superclass type (for example, passed it where an array was expected). Give them an explicit accessor or an interface.

## Watch out

- Do not use delegation when the subclass truly is a specialization and uses most of the superclass interface. You will write many trivial forwarding methods.
- Forwarding breaks `instanceof` checks and code that passes the object where the superclass type is expected.
- Calls that the superclass made to overridden methods (self-calls) no longer reach the former subclass. Check any template-method style hooks.
- The inverse technique is [Replace Delegation with Inheritance](https://aipatterns.dev/refactoring/techniques/replace-delegation-with-inheritance.md).

## Related

- Inverse: [Replace Delegation with Inheritance](https://aipatterns.dev/refactoring/techniques/replace-delegation-with-inheritance.md).
- Fixes [Refused Bequest](https://aipatterns.dev/refactoring/smells/refused-bequest.md) and reduces [Inappropriate Intimacy](https://aipatterns.dev/refactoring/smells/inappropriate-intimacy.md) with the superclass's internals.
- Often combined with [Extract Interface](https://aipatterns.dev/refactoring/techniques/extract-interface.md). The resulting structure underlies [Decorator](https://aipatterns.dev/design-patterns/decorator.md) and [Strategy](https://aipatterns.dev/design-patterns/strategy.md).

## Agent checklist

- [ ] The class uses only a small part of the superclass interface, or inherited methods break its rules.
- [ ] Only methods that callers need are forwarded.
- [ ] Callers relying on the superclass type or `instanceof` were updated.
- [ ] Former self-calls from the superclass into overrides were checked.
