composition-over-inheritance
Use when tempted to use class inheritance. Use when creating class hierarchies. Use when subclass needs only some parent behavior.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when tempted to use class inheritance. Use when creating class hierarchies. Use when subclass needs only some parent behavior.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when writing tests. Use when test structure is unclear. Use when arrange/act/assert phases are mixed.
Use when designing or modifying APIs. Use when adding breaking changes. Use when clients depend on API stability.
Use when implementing authentication. Use when storing passwords. Use when asked to store credentials insecurely.
Use when same data is fetched repeatedly. Use when database queries are slow. Use when implementing caching without invalidation strategy.
Use when acquiring multiple locks. Use when operations wait for each other. Use when system hangs without crashing.
Use when a class creates its own dependencies. Use when instantiating concrete implementations inside a class. Use when told to avoid dependency injection for simplicity.
| name | composition-over-inheritance |
| description | Use when tempted to use class inheritance. Use when creating class hierarchies. Use when subclass needs only some parent behavior. |
Favor object composition over class inheritance.
Inheritance creates tight coupling and rigid hierarchies. Composition creates flexible, reusable components that can be mixed and matched.
extendsNEVER use inheritance when composition would work.
No exceptions:
Default to composition. Use inheritance only for true type hierarchies.
If inheritance feels awkward or forced, use composition:
// ❌ VIOLATION: Inheritance hierarchy
class Animal {
eat(): void { console.log('Eating'); }
}
class FlyingAnimal extends Animal {
fly(): void { console.log('Flying'); }
}
class SwimmingAnimal extends Animal {
swim(): void { console.log('Swimming'); }
}
// Duck needs both fly AND swim - inheritance can't do this cleanly
class Duck extends FlyingAnimal {
swim(): void { console.log('Swimming'); } // Duplicated!
}
Define capabilities as interfaces, compose them:
// ✅ CORRECT: Composition
interface Flyable {
fly(): void;
}
interface Swimmable {
swim(): void;
}
interface Eatable {
eat(): void;
}
// Reusable behaviors
const flyingBehavior: Flyable = {
fly() { console.log('Flying'); }
};
const swimmingBehavior: Swimmable = {
swim() { console.log('Swimming'); }
};
const eatingBehavior: Eatable = {
eat() { console.log('Eating'); }
};
// Compose what you need
class Duck implements Flyable, Swimmable, Eatable {
fly = flyingBehavior.fly;
swim = swimmingBehavior.swim;
eat = eatingBehavior.eat;
}
class Fish implements Swimmable, Eatable {
swim = swimmingBehavior.swim;
eat = eatingBehavior.eat;
}
class Bird implements Flyable, Eatable {
fly = flyingBehavior.fly;
eat = eatingBehavior.eat;
}
| Problem | Example |
|---|---|
| Diamond problem | Duck needs Flying AND Swimming |
| Tight coupling | Child knows parent internals |
| Rigid hierarchy | Can't change parent without breaking children |
| Forced inheritance | Gets methods it doesn't need |
| Fragile base class | Parent changes break all children |
| Benefit | Example |
|---|---|
| Flexible | Mix any behaviors together |
| Loose coupling | Components don't know each other |
| Easy testing | Mock individual behaviors |
| Runtime changes | Swap behaviors dynamically |
| No hierarchy lock-in | Add new combinations freely |
Pressure: "Object-oriented programming uses inheritance"
Response: Modern OOP favors composition. Inheritance is overused.
Action: Use interfaces + composition. It's still OOP.
Pressure: "A Duck IS-A Bird, so it should extend Bird"
Response: "Is-a" often becomes "has-a" when requirements change. Composition handles both.
Action: Model as "has behaviors" not "is a type".
Pressure: "I need the parent's methods"
Response: Composition provides better code reuse without coupling.
Action: Extract shared behavior into composable units.
Pressure: "I need to treat different types uniformly"
Response: Interfaces provide polymorphism without inheritance.
Action: Define interface, have classes implement it.
If you notice ANY of these, use composition instead:
extends keyword in your codeAll of these mean: Refactor to composition.
Use inheritance only when:
Even then, keep hierarchy shallow (max 2 levels).
| Inheritance | Composition |
|---|---|
class Dog extends Animal | class Dog implements Animal + behavior injection |
| Rigid hierarchy | Flexible composition |
| Single parent only | Multiple behaviors |
| Tight coupling | Loose coupling |
| Changes cascade | Changes isolated |
| Excuse | Reality |
|---|---|
| "It's the OOP way" | Modern OOP prefers composition. |
| "It's an is-a relationship" | "Has behavior" is more flexible. |
| "Need parent's methods" | Compose the behavior instead. |
| "Polymorphism needs it" | Interfaces provide polymorphism. |
| "Less code with extends" | More flexibility with composition. |
| "I noted it's problematic" | Don't do it if it's problematic. |
Compose behaviors. Don't inherit them.
When designing classes: define interfaces for capabilities, create composable behaviors, inject what each class needs. Use extends only as last resort.