EnriqueMark
Design Patterns & Architecture

Composition and inheritance

2026-03 → updated 2026-09 English

The key reason for composition over inheritance is decoupling, or rather, modules like building blocks, with external state and side effects removed as far as possible. Ideally, compositions are atomic with respect to each other. Each one answers only for its own inside and doesn’t care about the outside. Classes are different. Inheritance by nature implies the opposite. Its key point is “sharing state and behavior”, and that creates coupling without anyone noticing. That’s the cost, but sometimes it really is needed. You can see this from when to use composition. When do you use it? Composition covers the difference between “has a” and “is a”. A class is literally “a kind of thing”, meaning they’re one species, sharing structurally fixed (as said above), predefined parent state (properties) and methods (the concrete behavior they implement).

And the coupling we’re talking about is exactly the hidden links this shared state brings. Parent and child share a piece of mutable state, but the parent has no idea what the classes below it extended. It can’t predict which part of itself a subclass depends on. Maybe you change something that doesn’t matter, and some other feature way off somewhere breaks. Or the other way round, some subclass changes a grandparent’s state, and its own parent, which uses that state, might break, and so on. That’s implicit dependency, consequences carried down the whole chain.

Normally, even with extension, nothing should go wrong when you use it. With good contracts, discipline in how you inherit, and test coverage, you really can keep a broken inheritance chain from turning into a production incident. But why do I have to make it this coupled at all? If the subclass just messes around, so the method errors out, or pulls off side effects nobody expected, then as long as you’re linked, it still breaks. In team development everyone only sees their own part, and with people coming and going, the ones before and the ones after don’t share information. Whoever writes the parent can’t cover everything. Once you open an extension point, all sorts of monsters can come out.

If I need to focus on the concrete implementation of state and behavior, and I want whoever depends on it later to “inherit” (literally) that content, then a base class with inheritance is the standard move, with nothing redundant about it. I can’t let a human be a Frankenstein, patched together out of a pile of unrelated “blocks”. Even if it runs in the end, it’ll be as confusing as Frankenstein’s monster. It moves, as I said above, but our sense of a human is that a human has its own inherent state, and that state has to be inherited rather than patched together. A human has to be an “is a”, so it isn’t the standard move at all, it’s an “anti-pattern”.

But in some cases composition is what we need, blocks, decoupled modules. It’s aimed at “has a”. If I only want a reusable feature, like Lego that snaps together anywhere, and it doesn’t depend on any fixed state either, composition couldn’t fit better. Whether you build a house or a helicopter out of it doesn’t interest me. As long as you can snap it together, you can use it.

And for composition, one thing that matters a lot is the “interface”. What’s an interface? If a class focuses on the concrete implementation of state and behavior, an interface focuses on constraining the structure itself. It doesn’t care about the implementation, only about what shape that implementation should be.

From another side, composition doesn’t exclude classes. Because composition is flexible, it can be put together anywhere, inside a class for example. Even in a class, there’s no need to stuff every utility method in as the class’s own behavior. That only bloats it with methods. When you need one, just use a composed utility. Why not? As long as a composition makes sure its input and output don’t change, it’s clear to whoever uses it.


Translation note. I wrote this in Chinese. This English version is an LLM translation, so the wording is not mine even though the thinking is. Original: 組合和繼承.