Is-a 是一种类型关系 — 通过继承建模(Car 是 )。 是一种关系 — 通过建模( )。选择正确的关系是核心建模决策。
VehicleCarEngine// IS-A → inheritance
class Vehicle { void move() {} }
class Car extends Vehicle { } // a Car IS A Vehicle
// HAS-A → composition
class Engine { void start() {} }
class Car2 {
private Engine engine = new Engine(); // a Car HAS AN Engine
void start() { engine.start(); } // delegate to the part
}
问自己:"X 是某种类型的 Y,还是 X 拥有/使用 Y?"
A Dog IS-A Animal → inheritance ✅
A Car HAS-A Engine → composition ✅
A Square IS-A Shape → inheritance ✅
A Manager HAS Employees → composition (a list) ✅
A Stack HAS-A list (not IS-A) → composition (see earlier pitfall) ✅
人们为了重用代码而选择继承,即使关系实际上是 has-a。如果你永远不会将子类替换为基类使用,那么它可能不是 is-a — 应该使用组合。
这种区分是"优先使用组合而非继承"背后的实际决策规则:选择真实的关系,而不是能省几行代码的那个。
正确的选择能保持层次结构浅层且诚实,并防止 Liskov 违规,其中某个"子类型"无法真正替代其父类。