Depend upon abstractions - Program to an interface
Depend upon abstractions. Do not depend upon concrete classes.
Program to an interface, not an implementation
Design principle: Program to an interface, not an implementation. "Program to an interface" really means "Program to a supertype."
The point is to exploit polymorphism by programming to a supertype so that the actual runtime object is not locked into the code. We could re-phrase it like this: The declared type of the variables should be a supertype, usually an abstract class or interface, so that the objects assigned to those variables can be of any concrete implementation of the supertype, which means the class declaring them doesn’t need to know about the actual object types.
Programming to an implementation:
Dog d = new Dog();
d.bark();
Dog is a concrete implementation of Animal.
Programming to an interface or supertype:
Animal a = new Dog();
a.makeSound();
Using the Animal reference polymorphically.
Even better, do not hard-code the instantiation of the subtype:
a = getAnimal();
a.makeSound();
Assign the concrete implementation object at runtime.
Another advantage with this approach is, other types of objects can reuse the fly and quack behaviors because these behaviors are no longer hidden away in the duck classes. And we can add new behaviors without modifying any of the existing behavior classes or touching any of the duck classes that use flying behaviors.