Skip to content

Inline Class

Take a class that has shrunk to almost nothing — a couple of fields and a method or two that no longer justify a separate type — and merge it into the class that holds it. The behaviour is unchanged; you have simply removed a layer that stopped earning its keep.

This is the inverse of Extract Class, and the cure for a class that has become a needless middle layer. The signs: a class with one field and a trivial method, a type that exists only to be wrapped by one caller, or a former responsibility that earlier refactorings have hollowed out. If reading the code means hopping to a tiny class and straight back, that hop is pure overhead.

A TrackingInformation class that holds two fields and formats them, used by a single Shipment. Before, the data and its one method sit in a separate type. After, they fold into Shipment.

// Before
class TrackingInformation {
constructor(public shippingCompany: string, public trackingNumber: string) {}
display(): string {
return `${this.shippingCompany}: ${this.trackingNumber}`;
}
}
class Shipment {
constructor(public trackingInfo: TrackingInformation) {}
status(): string {
return `Shipped via ${this.trackingInfo.display()}`;
}
}
// After
class Shipment {
constructor(public shippingCompany: string, public trackingNumber: string) {}
private trackingDisplay(): string {
return `${this.shippingCompany}: ${this.trackingNumber}`;
}
status(): string {
return `Shipped via ${this.trackingDisplay()}`;
}
}
classDiagram
  class ShipmentBefore {
    trackingInfo
    status()
  }
  class TrackingInformation {
    shippingCompany
    trackingNumber
    display()
  }
  class ShipmentAfter {
    shippingCompany
    trackingNumber
    status()
    trackingDisplay()
  }
  ShipmentBefore --> TrackingInformation : has a
  TrackingInformation ..> ShipmentAfter : Inline Class
A thin TrackingInformation folds back into Shipment
  1. On the absorbing class, declare the public methods of the class you are about to inline, and have each simply delegate to the inner instance for now.
  2. Update every caller of the soon-to-be-removed class to go through the absorbing class instead.
  3. Run your tests to confirm the delegation behaves identically.
  4. Move the inner class’s fields and methods into the absorbing class one at a time, using Move Field and Move Function.
  5. Replace each delegating method body with the real logic now living locally.
  6. Run your tests after each move so a failure points at a single step.
  7. Delete the now-empty class once nothing references it.

Inline a class when it has shrunk to a single field with trivial behaviour, when it exists only to wrap one caller, or when an earlier extraction never grew into a genuine responsibility and now just adds indirection.

The cost is that the absorbing class gets bigger, so do not inline a type that is still doing real, separable work — that is the road back to a Large Class. The inverse is Extract Class: if the merged class later sprouts a second responsibility, split it out again.

When is Inline Class the right move?
Inline Class is the inverse of which refactoring?
What is a risk of inlining a class that is still doing real work?
What is the recommended first step when inlining a class?