Let's start with
interface Fruit {}
class Apple implements Fruit {}
class Orange implements Fruit {}
Now we want to eat the fruit. But we can only eat Apples.
void eat(Fruit fruit) {
if (!(fruit instanceof Apple)) {
throw new IllegalArgumentException("I only like Apples!");
}
// Om nom nom....
}
So that's one way to only eat apples, but look! There's an if block, an instanceof check, and an unchecked exception. Plus now we need unit tests to make sure we reject these unsuitable Oranges. Bleh! Compare that to another way to eat only Apples:
void eat(Apple fruit) {
// Om nom nom....
}
Now the type checker won't let us eat() anything but Apples, which is what we were trying to do anyway. The problem with the first code is that we're lying about which types of input are acceptable in our method signature, and therefore we have to play catch-up with more complicated code in the method definition. We can and should choose to eat Apples if it's true that those are the only Fruit that does it for us. Less to write. Less to test. Fewer opportunities for mischief.
No comments:
Post a Comment