jueves, 16 de marzo de 2017

Programación Orientada a Objetos - Parte I

Tecnología de Programación Orientada a Objetos
En el paradigma de la programación moderna, se ha planteado el modelo de desarrollo de software llamado OOP (Programación Orientada a Objetos) que tiene incidencia en la significancia del desarrollo de sistemas basándose en un concepto más cercano a la realidad del mundo que nos rodea. Sin embargo, en el pasado el proceso de desarrollo de software se basaba en un concepto más abstracto, matemático o conocido por el método procedural y funcional. Por lo tanto, existen dos grandes paradigmas de la programación moderna:
  • El modelo TAD
  • El modelo OOP
Modelo TAD
El modelo de desarrollo conocido como (Tipo de Datos Abstracto) o también conocido por el modelo procedural, ha sido en un principio y hasta mediados de los ‘70, el más utilizado a lo largo del desarrollo del software. Se basa en un concepto altamente procedural y funcional. Su concepto de desarrollo estriba fuertemente en algoritmos elaborados y que se estructuran en procesos complejos. El desarrollo asume un modelo altamente funcional y que tiene procesos de código complejo y altamente estructurado. Su principal desventaja es la escala, es decir, a medida que el software crece en complejidad y funcionalidades, tiende a la engorrosidad, lo cual conlleva a procesos de depuración y construcción de sistemas más complejos y con mayores tendencias a errores, costos operativos, etc. Entre otras, no facilita la reutilización del código y tiende a duplicarlo masivamente.

Modelo OOP
El modelo OOP (Programación Orientada a Objetos), se basa en un concepto de desarrollo basado en un mundo más real, es decir, a un mundo más cercano al que conocemos los seres humanos. Este modelo surge a mediados de los ’60, en los ’70 se lo fue desarrollando en exclusividad y se hizo popular a comienzo de los ’80. Su principal elemento de justificación son los objetos. En el mundo que nos rodea, encontramos elementos que pueden ser tangibles e intangibles. Sin embargo, en ambos casos, hablamos de objetos. De hecho, los elementos intangibles que son conceptos que también se tratan de objetos. Por ejemplo, una cuenta bancaria. Si bien una cuenta bancaria no es tangible, en el mundo que conocemos, sabemos que existe y por lo tanto se trata de un objeto, es decir, se trata de un concepto mental. Respecto a los elementos tangibles se puede citar como por ejemplo un Banco donde se hacen operaciones financieras. Por ejemplo, un Banco existe dado que se trata de un objeto y puede ser un edificio o un lugar de operaciones financieras. En ambos casos, hacemos mención de algún tipo de objeto.
En resumen, podemos decir que los objetos se clasifican en dos grandes tipos:
  • Objetos Tangibles – Banco, automóvil, avión, barco, casa, edificio, etc.
  • Objetos Intangibles – Cuenta bancaria, una fórmula matemática,  etc.
¿Qué es un Objeto en Programación?

Un objeto en programación se trata de un elemento que tiene características que lo describen, tales como atributos y operaciones. Los atributos son sus propiedades de aspecto. Por ejemplo, si hablamos del objeto automóvil, sus propiedades pueden ser el color, el estilo, cantidad de puertas, etc. Las operaciones son las acciones que el objeto es capaz de realizar. Por ejemplo, el automóvil tiene las operaciones de arrancar, frenar, moverse, doblar, etc. En consecuencia, un objeto generalmente contiene atributos y operaciones.
Importante: Ud., debe identificar atributos y operaciones en un objeto en el dominio del problema. Si no es capaz de encontrar atributos u operaciones en el caso de estudio, debería formularse la pregunta de que si el objeto en cuestión se trata o no de un verdadero objeto. De no ser así, es muy probable que lo que se tenga como objeto de estudio, no se trate de un objeto en sí pero sí se trate como parte de algún otro objeto en cuestión. En este caso, se dice que el objeto forma parte de otro objeto más complejo y se define como un tipo de atributo o un tipo de operación y no como un tipo de objeto propiamente dicho.
Cuando un objeto forma parte de otro, se debe primero analizar si este mismo depende o no del otro objeto. Si existe una dependencia se considera a dicho dominio como una Composición entre ambos. Ahora bien, si no existe una dependencia entre ambos, entonces, se dice que es una Asociación entre ambos.
En consecuencia, un objeto se compone de dos elementos fundamentales y ellos son:
  • Atributos – Propiedades del objeto
  • Operaciones – Acciones que realiza el objeto
Composición y Asociación

Como señale recién en la observación del párrafo anterior, en el dominio del problema, identificar los objetos y sus interrelaciones resulta crucial. Un objeto podría depender de otro. Por ejemplo, si analizamos un motor de un automóvil, encontraremos que existen una serie de piezas que hace posible que este funcione. Si al motor, le sacamos una pieza, por ejemplo, los pistones internos, este mismo no podrá funcionar. En consecuencia, los pistones forman parte del motor. Por tanto, existe una estrecha dependencia entre los pistones y el motor. Esta dependencia se la conoce con el nombre de Composición.
Ahora bien, un objeto podría no depender de otro. Por ejemplo, si analizamos un reloj de pared. Como puede imaginar, el reloj contiene un cuadrante donde se aloja la maquinaria la cual se ensambla con las manecillas. Si le sacamos las manecillas, el reloj no podría indicarnos la hora, sin embargo, su maquinaria seguirá funcionando normalmente. Acá podemos ver que la maquinaria del reloj no depende de las manecillas para su funcionamiento. Por tanto, las manecillas se asocian al reloj para cumplir la función de indicarnos la hora. A este efecto se lo conoce con el nombre de Asociación. En toda asociación, no existe una estrecha dependencia de los objetos entre sí.

¿Qué es un Clase?


Una clase se trata de un tipo de objeto cuyo propósito sirve como elemento para crear otros tipos de objetos reutilizables en el sistema. Es una suerte de molde que permite dar forma a los objetos destino.
Las clases, suelen ser llamadas como “librerías” que tienen un propósito de creación para desarrollar tipos de objetos o clases más específicas. La clase principal, suele ser llamada Genérica o Generalizada, debido a que se compone de atributos y operaciones sencillos.
Estos atributos y operaciones sencillas permiten el desarrollo de la mayoría de las clases que están por debajo de ellas. Las clases que son producto de una elaboración de clases superiores y que incluyen mayor cantidad de operaciones y atributos, suelen ser más Específicas. En conclusión, viendo el proceso como un árbol, dirigiéndose hacia las hojas del árbol, se encuentran las clases más específicas, refinadas, elaboradas con estructuras especiales, mientras que si nos dirigimos hacia la raíz, nos encontraremos con clases base o generalizadas, debido a que estas carecen de la mayoría de los atributos y operaciones que el resto de las clases elaboradas contienen. Esta condición de simplicidad resulta suficiente para el propósito de la herencia y la creación de clases más específicas.
En el ejemplo de la figura 9-1 de la derecha, se marca la jerarquía de la generalización hacia la especificación. Cada una de las clases que hereda de su superior se especializa más, cada vez que crece la herencia a medida que se va extendiéndose hacia otros tipos de clases.
En la figura de abajo, se vuelca un ejemplo de generalización a especificación con objetos de la vida real. La herencia de los objetos más específicos, parten de la herencia base que permite especificar a las clases inferiores que resultan ser específicas. Obsérvese que todos tienen la facilidad de transportarse y cada uno de ellos lo hará de forma diferente y bajo determinadas especificaciones. Simplemente, piense en el tablero de control del automóvil, del avión y del tren; luego, el manubrio de la bicicleta y las riendas del caballo. Verá que existen diferentes especificaciones que no se encuentran en la clase Transporte. Estas mismas les son propias de cada una de estas clases. De allí el término de la especificación. Véase el siguiente ejemplo.




Tipos de Herencias
En la tecnología OOP se conocen dos tipos de herencias importantes y ellas son:
  • Herencia Múltiple
  • Herencia Simple
La herencia múltiple es utilizada en los lenguajes tales como el C++, SmartTalk, etc. Su propósito es similar al que explicamos recientemente, pero tiene como característica fundamental la propiedad de heredar de más de una clase base. Esto tiene sus ventajas y sus desventajas. La herencia múltiple es muy compleja y ha sido un proceso exclusivo para lenguajes muy robustos y complejos como lo es el C++, entre otros.
La herencia simple, es la que hemos visto de forma introductoria en el apartado anterior. Tiene un mecanismo que solo permite heredar de una clase base a la vez, es decir, no permite heredar de más de una clase base a la vez. Esta característica que parece mezquina si se la compara con la herencia múltiple, sin embargo, resulta ser más segura. Es por ello que los modernos lenguajes de programación basada en plataformas Framework .NET y la plataforma JVM (Java Virtual Machine) de JAVA, utilizan herencia simple.

¿Por qué usar Herencia Simple y no Múltiple?
La respuesta a esta pregunta resulta muy sencilla. Véase el siguiente ejemplo de herencias simples y complejas.
Nótese que la herencia simple tan solo hereda de una clase base mientras que la herencia múltiple hereda de más de una clase base. En el caso de la herencia múltiple, la herencia se hace más compleja debido a que cuando se pasan los atributos y las operaciones a las clases heredadas, la complejidad aumenta, lo cual dificulta la implementación, hace más compleja la construcción de sobrecargas y sobrescritura de operaciones, etc. Además, no queda claro las especializaciones de las clases. Es más, quizá el elemento más peligroso que puede ocurrir en una herencia múltiple es la pérdida, modificación o alteración de las clases padres. Si una de las clases padres se perdiera por alguna razón, se dice que los atributos y operaciones heredades de esa clase, en las clases inferiores, quedarían huérfanas. Por tanto, resultaría más compleja en depurar y corregir dichos errores. Esto significa un enorme problema en un sistema y es por ello que la herencia múltiple implica un moderado modelo de construcción que resulta muy dificultoso de mantener y elaborar.
En cambio, la herencia simple no permite la herencia de más de un padre como clase superior, sin embargo, brinda una mayor confiabilidad. La pérdida de la clase padre si bien deja huérfana a las clases inferiores, supone un problema más sencillo de resolver. Entre otras ventajas, contamos con que el código se hace más legible y amigable, se tiende menos a la complejidad y se escala de una forma más moderada y segura. Como elemento paliativo a la herencia múltiple y que resuelve el conflicto de las múltiples herencias, las plataformas Framework .NET y JAVA, permiten la múltiple herencia de interfaces, lo que potencia enormemente las funcionalidades del entorno de desarrollo.
El estándar moderno de desarrollo OOP ha establecido como protocolo de normalización que la herencia debe ser simple, de manera que simplifique el modelo de interpretación, legibilidad y facilite la escala en el desarrollo del software. Esto apareja mejor los desarrollos de sistemas y abarata los costes significativamente. 

Polimorfismo
Cuando una clase hereda de otra,  la clase base le pasa sus atributos y operaciones según sus alcances  a la clase destino o clase heredada. Este proceso directo es conocido con el nombre de herencia. El polimorfismo es un comportamiento particular de este proceso. Cuando una operación, en este caso un método, pasa hacia otra clase y mientras que la semántica  no cambie y se preserve, la regla polimórfica se cumple. Cuando la semántica cambia, deja de ser polimorfismo.
Por ejemplo, supóngase que tiene una clase base llamada Felino. Luego, dos clases heredadas llamadas Gato y León. El método comer() resulta ser igual en aplicación tanto para un gato como para un león. Ambos utilizan su boca para deglutir los alimentos. En la implementación del código, se hereda dos métodos que se usarían en cada una de esas clases heredadas de forma similares. Sin embargo, si se adhiere una case heredada más llamada Automóvil, el método comer() si bien por sentido común no es aplicable, podría llegar a ser viable su uso. Suponiendo entonces que el método comer() pudiera ser implementado, la semántica del método en la clase Automóvil será totalmente distinta que en las clases Gato y León. He aquí el concepto de polimorfismo. Veamos el ejemplo de polimorfismo para las siguientes clases de forma gráfica.


Extracto de mi Libro - Capítulo 9 - Programación en C#
Autor: Wagner, Ariel Alejandro.
21-02-2014 - (Última actualización)
Muchas gracias por leer. 
Si encuentra interesante este material, puede donar lo que desee. Con su aporte, por más pequeño que sea, será suficiente para mentener este blog operacional. Nuevamente, muchas gracias. Que Dios lo bendiga.
- Ariel.

No hay comentarios:

Publicar un comentario