Clase Abstracta
¿Cuando puedo utilizar una clase abstracta?
únicamente se utilizará para definir subClases, por lo tanto siempre deberá ser heredada para poder heredar y sobreescribir los métodos de su clase padre.
Una restricción de esta clase es que, naturalmente, no se podrá crear instancias a partir de ella. Únicamente podrá ser heredada. Por lo tanto la herencia de métodos se llevará de forma lineal, desde una clase padre a una clase hija y así sucesivamente.
Herencia de métodos en clases abstractas de forma Lineal
Podemos heredar métodos abstractos y no abstractos.
Por lo tanto una Clase abstracta nos servirá para redefinir nuevas Clases sin crear nuevos Objetos.
Interfaz
¿Cuando puedo utilizar una Interfaz?
En una interfaz tenemos nuevos modificadores de Acceso Default y Private, esto significa que podemos agregar comportamiento a los métodos de una interfaz. Entonces una interfaz, ahora, tendra métodos con implementación y otros sin implementación, igual que en una clase abstracta.
En la interfaces tendremos una estructura similar de métodos abstractos y no abstractos. Pero acá la vista principal será sobre los métodos que estos pueden implementarse en muchas familias de Clases. La implementación de estos métodos dejará de ser Lineal, como en la clases abstractas.
La implementación de métodos de interfaces no es Lineal
¿Cuando implementar cada una?
Usaremos interfaces para implementar métodos que se comparten entre familias, es decir, la relación va más allá de la herencia entre dos clases.
Otra diferencia es la forma en como nombramos una clase abstracta y una interfaz. En la Abstracta pensaremos mas en objetos y en la interfaces pensaremos más en las acciones, comportamientos, que pueden tener en común muchos objetos.
Es común encontrar nombres en forma de acciones como Drawable (Dibujable), Runnable (Ejecutable), Callable (invocable), Visualizable (Visualizable) para interfaces. Y para clases abstractas tendremos nombres sustantivos como Film, Publication, Figure.
Buenas prácticas
Una buena práctica es que el diseño de las aplicaciones, siempre, esté orientado a interfaces y no a la implementación.
Crear buenas abstracciones para encontrar comportamientos en común.
Enfocarse en la declaración de métodos.
Si se trata de forma homogenea y con independencia los módulos, el programa será más eficiente y escalables