# Replace Delegation with Inheritance

> When a class forwards nearly every call to one delegate it truly is a kind of, make it a subclass of that delegate and delete the forwarding.

- kind: technique
- category: dealing-with-generalization
- canonical: https://aipatterns.dev/refactoring/techniques/replace-delegation-with-inheritance
- inspired-by: https://refactoring.guru/replace-delegation-with-inheritance

## Problem

A class holds an instance of another class and forwards almost every method to it unchanged. Each new method on the delegate needs another forwarding method. The class is really a specialization of the delegate, but it is written as a wrapper.

## Solution

**Make the class extend the delegate's class, remove the delegate field, and delete the forwarding methods.** Keep only the methods that add or change behavior.

## Before

```ts
class HttpClient {
  constructor(protected baseUrl: string) {}
  get<T>(path: string): Promise<T> { /* ... */ }
  post<T>(path: string, body: unknown): Promise<T> { /* ... */ }
  put<T>(path: string, body: unknown): Promise<T> { /* ... */ }
  delete(path: string): Promise<void> { /* ... */ }
}

class BillingApiClient {
  private http = new HttpClient("https://billing.internal/v2");

  get<T>(path: string) { return this.http.get<T>(path); }
  post<T>(path: string, body: unknown) { return this.http.post<T>(path, body); }
  put<T>(path: string, body: unknown) { return this.http.put<T>(path, body); }
  delete(path: string) { return this.http.delete(path); }

  invoice(id: string) { return this.http.get<Invoice>(`/invoices/${id}`); }
}
```

## After

```ts
class HttpClient {
  constructor(protected baseUrl: string) {}
  get<T>(path: string): Promise<T> { /* ... */ }
  post<T>(path: string, body: unknown): Promise<T> { /* ... */ }
  put<T>(path: string, body: unknown): Promise<T> { /* ... */ }
  delete(path: string): Promise<void> { /* ... */ }
}

class BillingApiClient extends HttpClient {
  constructor() {
    super("https://billing.internal/v2");
  }

  invoice(id: string) { return this.get<Invoice>(`/invoices/${id}`); }
}
```

## Why

- The forwarding boilerplate disappears, along with the work of keeping it in sync.
- New methods on the base class are available automatically.
- The class shrinks to what makes it different.

## Steps

1. Confirm the class uses the whole delegate interface and that nothing else holds a reference to the same delegate instance.
2. Make the class extend the delegate's class. If a forwarding method has the same name, it now overrides the inherited one and still works. Run the tests.
3. Initialize the superclass through `super(...)` with what the delegate was constructed with. Point the delegate field at `this`. Run the tests.
4. Delete forwarding methods one at a time; the inherited versions take over. Run the tests after each.
5. Replace remaining uses of the field with `this`, then delete the field. Run the tests.

## Watch out

- Do not do this if the class uses only part of the delegate. Inheritance exposes the whole interface, which is the [Refused Bequest](https://aipatterns.dev/refactoring/smells/refused-bequest.md) problem the inverse technique exists to fix.
- Do not do this when the delegate is shared with other objects or swapped at runtime. A superclass cannot be shared or replaced.
- If the class already extends something else, single-inheritance languages block this. Consider [Remove Middle Man](https://aipatterns.dev/refactoring/techniques/remove-middle-man.md) so clients call the delegate directly.
- Inheritance couples you to the base class's protected internals and future changes. In the example, a `BillingApiClient` now publicly exposes generic `delete(path)`; decide whether that is acceptable.
- The inverse technique is [Replace Inheritance with Delegation](https://aipatterns.dev/refactoring/techniques/replace-inheritance-with-delegation.md).

## Related

- Inverse: [Replace Inheritance with Delegation](https://aipatterns.dev/refactoring/techniques/replace-inheritance-with-delegation.md).
- Fixes [Middle Man](https://aipatterns.dev/refactoring/smells/middle-man.md).
- Alternative: [Remove Middle Man](https://aipatterns.dev/refactoring/techniques/remove-middle-man.md).

## Agent checklist

- [ ] The class forwards nearly all of the delegate's public methods unchanged.
- [ ] The delegate is not shared with other objects or replaced at runtime.
- [ ] The class does not already need a different superclass.
- [ ] Exposing the full inherited interface is acceptable for callers.
