A pedido de exizt, estoy ampliando mi comentario a una respuesta más larga.
El mayor error que comete la gente es creer que las interfaces son simplemente clases abstractas vacías. Una interfaz es una forma para que un programador diga: "No me importa lo que me des, siempre y cuando siga esta convención".
La biblioteca .NET sirve como un maravilloso ejemplo. Por ejemplo, cuando escribe una función que acepta un IEnumerable<T>
, lo que está diciendo es: "No me importa cómo está almacenando sus datos. Solo quiero saber que puedo usar un foreach
bucle.
Esto lleva a un código muy flexible. De repente, para integrarse, todo lo que necesita hacer es seguir las reglas de las interfaces existentes. Si la implementación de la interfaz es difícil o confusa, entonces tal vez sea una pista de que estás tratando de meter una clavija cuadrada en un agujero redondo.
Pero luego surge la pregunta: "¿Qué pasa con la reutilización del código? Mis profesores de CS me dijeron que la herencia era la solución a todos los problemas de reutilización del código y que la herencia le permite escribir una vez y usar en todas partes y curaría la menangitis en el proceso de rescate de huérfanos de los mares crecientes y no habría más lágrimas y así sucesivamente, etc., etc., etc. "
Usar la herencia solo porque te gusta el sonido de las palabras "reutilización de código" es una muy mala idea. La guía de estilo de código de Google hace este punto bastante conciso:
La composición es a menudo más apropiada que la herencia. ... [B] ya que el código que implementa una subclase se extiende entre la base y la subclase, puede ser más difícil entender una implementación. La subclase no puede anular funciones que no son virtuales, por lo que la subclase no puede cambiar la implementación.
Para ilustrar por qué la herencia no siempre es la respuesta, voy a usar una clase llamada MySpecialFileWriter †. Una persona que cree ciegamente que la herencia es la solución a todos los problemas, argumentaría que debe tratar de heredar FileStream
, para no duplicar FileStream
el código. Las personas inteligentes reconocen que esto es estúpido. Simplemente debe tener un FileStream
objeto en su clase (ya sea como una variable local o miembro) y usar su funcionalidad.
El FileStream
ejemplo puede parecer artificial, pero no lo es. Si tiene dos clases que implementan la misma interfaz exactamente de la misma manera, entonces debe tener una tercera clase que encapsule cualquier operación que esté duplicada. Su objetivo debe ser escribir clases que sean bloques reutilizables autónomos que se puedan juntar como legos.
Esto no significa que la herencia deba evitarse a toda costa. Hay muchos puntos a considerar, y la mayoría se cubrirá investigando la pregunta "Composición vs. Herencia". Nuestro propio Stack Overflow tiene algunas buenas respuestas sobre el tema.
Al final del día, los sentimientos de su compañero de trabajo carecen de la profundidad o comprensión necesarias para tomar una decisión informada. Investiga el tema y descúbrelo por ti mismo.
† Al ilustrar la herencia, todos usan animales. Eso es inútil. En 11 años de desarrollo, nunca he escrito una clase llamada Cat
, así que no voy a usarla como ejemplo.
alligator
La implementación deeat
difiere, por supuesto, en que aceptacat
ydog
como parámetros.