to relacja — modelowana za pomocą (samochód ). to relacja — modelowana za pomocą (samochód ). Wybór właściwej z nich to kluczowa decyzja modelowania.
to relacja — modelowana za pomocą (samochód ). to relacja — modelowana za pomocą (samochód ). Wybór właściwej z nich to kluczowa decyzja modelowania.
CarVehicleCarEngine// 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
}
Zapamiętaj: "Czy X jest rodzajem Y, czy X posiada 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) ✅
Ludzie sięgają po inheritance, aby ponownie użyć kod, nawet gdy relacja jest naprawdę has-a. Jeśli nigdy nie zastąpisz podklasy bazą wszędzie, to prawdopodobnie nie jest is-a — użyj composition.
To rozróżnienie jest praktyczną regułą decyzyjną stojącą za "preferuj composition zamiast inheritance": wybierz relację, która jest prawdziwa, a nie tę, która oszczędza kilka linijek.
Zrobienie tego dobrze utrzymuje hierarchie płytkie i szczere, a także zapobiega naruszeniom Liskowa, w których "podtyp" nie może faktycznie zastąpić swojego rodzica.