Card 07/ 09
All 9 cards
ComparisonDifficulty: Advanced1 min
A Polymorphic Call Against a Chain of instanceof
Both shapes work. One puts the behaviour on the types and one puts it in the caller, and which is right depends on something specific: whether the set of types or the set of operations changes more often.
| Compared on | A method on each type | A chain of instanceof in the caller |
|---|---|---|
| Adding a new type | One new class; nothing else is touched | Every chain must be found and extended |
| Adding a new operation | Every class must gain a method | One new method in one place |
| Missing a case | The compiler refuses the class | Falls through the chain, silently |
| Where the behaviour lives | Beside the data it uses | Away from it, in the caller |
The decision rule. When new types arrive more often than new operations — payment methods, shapes, report formats — put the method on the type. When the types are fixed and closed and the operations keep coming, the chain in the caller is the honest shape.
Java 21 makes the second case safe rather than merely tolerable. A switch with pattern labels over a sealed type is checked for exhaustiveness by the compiler, so the silent fall-through in row three stops being possible.
String describe(Shape s) {
return switch (s) {
case Circle c -> "circle of " + c.radius();
case Square q -> "square of " + q.side();
case Line l -> "line";
};
}What has not changed is the first row. Adding a fourth shape still means finding this method, and the compiler will now make sure you do. A build that refuses is a much better failure than a cast that throws on one record in production.