21 de marzo de 2017

Herencia / Generalización

   Uno de los conceptos del paradigma orientado a objetos más importantes es el de herencia, ya que dicho mecanismo de abstracción permite la re utilización de código de una manera sumamente conveniente, además de habilitar las capacidades del polimorfismo a través de la sobre escritura (override) de métodos.

   Abstracción.
   La ejemplificación del concepto de herencia/generalización estará basada en los Ejemplo Persona y el Ejemplo Cientifico para Java, y en el Ejemplo Herencia para C++; pero antes de poder describirlos, considero pertinente presentar primero en un diagrama de clases los detalles de la relación de generalización que se quiere mostrar con la finalidad de elevar el nivel de abstracción. Con el diagrama de clases propuesto, se pretende llevar el concepto de herencia/generalización a la forma en que la mayoría de las personas comprendemos y analizamos las cosas, para posteriormente profundizar con más conocimiento de causa en los detalles de la implementación de dicho concepto en un lenguaje de programación.

   El diagrama de clases UML (Unified Modeling Language) del que partirá el análisis se muestra en la siguiente figura:
 
Diagrama de clases UML para mostrar la relación de generalización / herencia entre Científico y Persona.

    Los detalles completos de la explicación de un diagrama de clases UML quedan fuera de los alcances de este blog, por lo que sólo se describirán los aspectos más relevantes que ayuden al lector a visualizar de mejor manera, en caso de que el lector no cuente con experiencia en UML, la relación de generalización y herencia.

   Un diagrama de clases UML está compuesto, grosso modo, por clases y las relaciones entre dichas clases. En este sentido, cada clase se representa con un recuadro dividido en tres partes:
  1. Identificador de la clase.
  2. Listado de atributos con la especificación de su clase (tipo) y sus niveles de acceso correspondientes.
  3. Listado de métodos con la especificación de la clase (tipo) de sus argumentos y valor o clase de retorno, así como los niveles de acceso correspondientes para los métodos.
   Tanto para el caso de los atributos como para el de los métodos, los niveles de acceso están representados por un signo de más para un acceso público (+), un signo de menos para un acceso privado (-), y un signo de gato para un nivel de acceso protegido (#).

   Con base en lo anterior, puede observarse de nuestro diagrama que la clase Persona, y por lo tanto las instancias (objetos) que se deriven de ella, tendrán las siguientes características (atributos) comunes a una persona: un nombre, una edad, y una nacionalidad (podrían definirse mucho más características u otras diferentes a las descritas aquí, pero no es la intención del ejemplo representar todas las características completas y comunes a una persona). Observe también que se ha definido un conjunto de operaciones, acciones, responsabilidades o comportamiento comunes a una persona, mismas que se encuentran definidas por los métodos establecidos (al igual que para los atributos, no se ha pretendido modelar por completo el comportamiento o las responsabilidades representadas en los métodos, sino sólo una representación muy general).

   Con base en las aclaraciones previas y lo descrito hasta aquí, es posible decir que una persona promedio está representada de manera muy general por la clase Persona.

   Ahora bien, un científico es (recuerde la idea de división en especializaciones: relación is-a presentada en la entrada Orientación a objetos (conceptos)) una persona, y por lo tanto comparte las características o atributos así como las acciones o el comportamiento inherentes a una persona; y es precisamente este tipo de relación de compartir la que se refiere a la herencia, ya que se dice que en la herencia una clase hereda (comparte) los atributos (características) y métodos (acciones) a otra.

   La herencia en UML se representa por medio de una flecha como la de la figura anterior (diagrama de clases). Es importante señalar que el sentido de la flecha es sumamente significativo, ya que tal y como aparece en nuestra figura, el diagrama indica que la clase Científico hereda las características y el comportamiento de la clase Persona (y no al revés). Otra forma de verlo es que la clase Persona es una generalización de la clase Científico en el sentido de que esta última agrega cierto nivel de especificación respecto de la primera.

   Note también que la clase Científico define un atributo adicional (especialidad), mismo que se añade a todos los atributos que implícitamente ya tiene, mismos que fueron heredados de la clase Persona. Observe también que se han definido cuatro métodos para la clase Científico los cuales tienen las siguientes características:
  1. estableceEspecialidad: es un método de tipo set para el atributo especialidad definido en la clase Científico.
  2. obtenEspecialidad: es un método de tipo get para el atributo especialidad definido en la clase Científico.
  3. mensaje: este método ya estaba definido en la clase Persona, pero al ser redefinido en la clase Científico, se dice que sobre escribe (override) al primero, lo cual significa que un objeto instanciado de la clase Científico, responderá al mensaje mensaje con la definición de su propio método y no con la definición del método mensaje definido en la clase Persona.
  4. mensajeEspecial: este es un nuevo método particular y específico a las instancias derivadas de la clase Científico.
   Es fundamental que el lector se asegure de comprender la descripción hasta aquí realizada respecto a las clases PersonaCientífico. Es también muy importante entender la relación existente entre estas clases antes de continuar a la siguiente sección, en donde entre otras cosas, se abordarán los aspectos relacionados con la implementación de ellas en el lenguaje de programación correspondiente.