Programas ejemplo. Ligaduras Dinámicas. Capitulo 1 INTRODUCCIÓN A LA PROGRAMACIÓN ORIENTADA A OBJETOS (POO) Un poco de historia de la POO. La programación de computadoras es una actividad humana que se ha desarrollado casi enteramente durante la segunda mitad del siglo XX. Por lo tanto podemos suponer que aún está en sus orígenes y que el futuro traerá todavía grandes adelantos técnicos y teóricos que mejorarán sus resultados. En su corta historia, la programación ha sufrido importantes cambios, diríamos “casi revoluciones”. Los primeros avances metodológicamente ordenados, fueron protagonizados principalmente por Wirth, Dijstra y de forma menos teórica pero quizás con más impacto por Kernighan y Ritchie. Es lo que se denominó la programación estructurada. Los primeros lenguajes de programación eran simplemente instrucciones que se le podían dar a un autómata como una computadora, para que realizara ciertas operaciones. Así un programa no era sino una lista de instrucciones encaminadas a realizar algún cálculo. A medida que las computadoras fueron haciéndose más sofisticadas, sus lenguajes propios o lenguajes de máquina iban cambiando y surgió la necesidad de crear unos lenguajes intermedios que cualquier usuario pudiera aprender y que no dependieran de la máquina concreta en la que se iban a ejecutar los programas. Así surgieron varios lenguajes que se hicieron famosos y también surgieron los primeros compiladores. Un compilador es un programa que traduce las instrucciones de un lenguaje más o menos humano, a las de una máquina. La aparición de estos lenguajes intermedios y sus compiladores marca el comienzo de la programación como una nueva ciencia. El tremendo éxito que las computadoras tuvieron a lo largo de los años 60 fue llevando a la creación de programas cada vez más complejos que llegaban a tener miles de líneas de código. Hacer correcciones a este tipo de programas y agregarles mejoras se fue convirtiendo en una labor muy ardua. Ante este problema que amenazaba con convertir las computadoras en máquinas estériles, surgió un grupo de científicos de la computación, de los cuales Dijstra y Wirth son dos de los más destacados. Estos propusieron una serie de ideas que llevaron a la creación de ese nuevo concepto indicado al inicio: la programación estructurada. Otros científicos experimentaron ideas similares creando diversos lenguajes de programación orientada a objetos como Smalltalk. En ellos se experimentó con otras ideas útiles como la definición de subclases que heredan las propiedades de su superclase o sea de la clase de la que se derivan, pero agregando variables y funciones nuevas. También surgió una idea que ayudaría a evitar los difíciles problemas que surgían en el manejo de la memoria dinámica: los constructores y destructores de objetos. Programas ejemplo. Ligaduras Dinámicas. A principios de los 90 se popularizó un nuevo lenguaje orientado a objetos. Se trata del C++ creado por Bjarne Stroustrup. La idea de Bjarne Stroustrup fue crear un lenguaje orientado a objetos que heredara prácticamente toda la sintaxis y posibilidades del lenguaje que en ese momento era más popular entre los programadores, el lenguaje C. Este truco ayudó a popularizar la programación orientada a objetos y preparó el camino para la aparición del Java. Los creadores de Java aprendieron bien la lección de Bjarne Stroustrup. Un nuevo lenguaje para tener éxito debía ser muy parecido al que en el momento de su lanzamiento fuese el más popular. Así, Java se creó con un gran parecido al C++. Pero Java es un lenguaje más puro de programación orientada a objetos, conserva un poco del C original, pero se parece más al C++. Puede verse al C++ como un paso intermedio en la transición de la programación estructurada del C a la programación orientada a objetos más pura del Java. Microsoft está tratando de impulsar un nuevo lenguaje llamado C# (C sharp) que promete ser aún más puro como lenguaje orientado a objetos, adopta prácticamente todas las mejoras de Java y agrega algunas nuevas. Habrá que estar pendientes una vez lanzado a los programadores de sus posibles ventajas y probables desventajas (en computación nunca se gana algo sin perder otra cosa, lo importante es que en promedio las cosas vayan mejorando). Hacia los 80’s el paradigma orientado a objetos comenzaba a madurar como un enfoque concreto de desarrollo de software. En los últimos años esta metodología ha experimentado un gran progreso, tanto en el desarrollo de programas como en la forma de presentar las aplicaciones del sistema al usuario. Actualmente la Tecnología Orientada a Objetos (TOO) no solo se aplica a los lenguajes de programación, sino que también se ha propagado a los métodos de análisis y diseño y a otras áreas, tales como las bases de datos y/o las comunicaciones. Por lo tanto, para hacer desarrollo de sistemas de software basados en la TOO, hay que entender bien todos los conceptos del modelo de objetos que está detrás de ella y sus antecedentes históricos. Uno de los defectos de la programación imperativa es que las variables globales pueden ser utilizadas y modificar sus contenidos, desde cualquier punto del programa. Los programas que carecen de disciplina para acceder a variables globales tienden a ser inmanejables. La razón es que los módulos que acceden a estas variables no se pueden comprender completamente, de forma independiente, de todos aquellos otros módulos que también acceden a las mismas variables globales, es decir, todo está relacionado con todo. Este problema fue detectado alrededor de 1970 por David L. Parnas, quien propuso la norma de ocultar información como solución. Su idea era encapsular cada una de las variables globales del programa en un módulo junto con sus operaciones asociadas, sólo mediante las cuales se podía tener acceso a estas variables. El resto de los módulos podrían acceder a las variables sólo de forma indirecta mediante las operaciones diseñadas a tal efecto. En la actualidad denominamos objetos a este tipo de módulos. El primer lenguaje que introdujo los conceptos de orientación a objetos fue SIMULA 67 creado en Noruega, por un grupo de investigadores dirigido por O. J. Dahl y K. Nygaard, con el fin de realizar simulaciones discretas de sistemas reales. Programas ejemplo. Ligaduras Dinámicas. En estos tiempos no existían lenguajes de programación que se ajustaran a sus necesidades, así que se basaron en el lenguaje ALGOL 60 y lo extendieron con conceptos de objetos, clases, herencia, el polimorfismo por inclusión (que se obtiene introduciendo la herencia de clases) y procedimientos virtuales. El lenguaje fue utilizado sobre todo en Europa y no tuvo mucho impacto comercial, sin embargo los conceptos que se definieron en él, se volvieron sumamente importantes para el futuro del desarrollo de software. La programación estructurada propone dos ideas básicas: no repetir código y proteger las variables que una parte del programa usa, de que sean modificadas accidentalmente por otras partes del programa. Una sola repetición de código es fuente probable de errores y dificulta el mantenimiento de un programa. Para no repetir código hay que escribir funciones o procedimientos que se encarguen de realizar siempre lo que las diferentes repeticiones realizarían. Para proteger las variables hay que desarrollar lenguajes que permitan definir variables locales, es decir, que sólo pueden ser utilizadas dentro de una función o procedimiento. De esta manera ninguna otra función del programa puede cambiarla. Como consecuencia de estas ideas disminuye considerablemente el tamaño de los programas y éstos se hacen más confiables y más fáciles de corregir o mejorar. Para facilitar la programación estructurada, aparecen nuevos lenguajes, notoriamente el Pascal y el C, son los dos lenguajes de programación estructurada más conocidos. Wirth, creador del Pascal, nunca quedó satisfecho con este lenguaje. En su constante análisis de los hábitos de programación encontraba que todavía había muchas cosas que mejorar. Una década después del Pascal publicó otro lenguaje llamado Modula2 en el que presentaban algunas de sus ideas más recientes. Los módulos de Modula2 pretendían representar objetos o clases. Dentro de un módulo se definían variables que representaban el estado del objeto y se definían procedimientos que describían su comportamiento. Las variables y los procedimientos de un módulo podían ser de uso público o privado, exclusivos de la clase, según lo decidiera el creador del módulo. Con todo esto se mejoraba notoriamente lo instituido por el Pascal donde el concepto de procedimientos o funciones privadas no existía y se daba un paso importante hacia la programación de clases o programación orientada a objetos. Alrededor de los años 70’s fue desarrollado el lenguaje de programación OO llamado SMALLTALK en los laboratorios Xerox en Palo Alto, EE.UU. Éste lenguaje adoptó los conceptos nombrados anteriormente como su fundamento. El hecho de ser creado en EE.UU., ayudó a que se introdujera a escala mundial el término de Orientación a Objetos (Object Oriented OO) y que cobrara importancia entre los diseñadores de lenguajes de programación. Los puntos importantes de este lenguaje fueron, por un lado, adoptar el concepto de objeto y clase como núcleo del lenguaje y la programación interactiva, incorporando las ideas ya conocidas de lenguajes funcionales. Es decir que se tuviese un lenguaje interpretado y no compilado. En 1985, Bjarne Stroustrup extendió el lenguaje de programación C a C++, es decir C con conceptos de clases y objetos, cerca de esta fecha, 1986, se creó desde sus bases el lenguaje EIFFEL por B. Meyer. Ambos manejan conceptos de objetos y herencia de clases. La herencia es múltiple, y se introduce pensando en dar mayor Programas ejemplo. Ligaduras Dinámicas. flexibilidad a los desarrolladores. Sin embargo, actualmente la herencia múltiple se ha evitado por agregar complejidad en las estructuras de clases. Ambos lenguajes tuvieron importancia entre 1985 y hasta la primera mitad de los 90’s. En 1995 apareció JAVA, el más reciente lenguaje OO, desarrollado por la empresa SUN Microsystems, que hereda conceptos de C++, pero los simplifica y evita la herencia múltiple. En su lugar se introduce el término de interfaz, y la herencia múltiple de interfases. Obtiene una rápida aceptación gracias a los applets, que son programas en JAVA insertados en páginas WEB dentro del código HTML. Estos programas pueden viajar a través de la Internet y brindarle al usuario mayor interactividad con las páginas WEB. JAVA introduce también, la programación concurrente y distribuida. El lenguaje es mitad compilado y mitad interpretado dando como resultado la portabilidad a distintas plataformas. JAVA aun sigue evolucionando y se espera que en los próximos años logre la madurez adecuada para convertirse en un lenguaje de desarrollo de mayor importancia. Ideas básicas de la POO La programación orientada a objetos es una metodología que descansa en el concepto de objeto para imponer la estructura modular de los programas. Permite comprender el dominio del problema a resolver, al intentar construir un modelo del mundo real que envuelve nuestro sistema. Es decir, la representación de este mundo mediante la identificación de los objetos que constituyen el vocabulario del dominio del problema, su organización y la representación de sus responsabilidades. El paradigma orientado a objetos se basa en los tres métodos de organización que utilizamos desde nuestra infancia y en los que basamos todo nuestro pensamiento: a) la diferencia entre un objeto y sus atributos (por ejemplo, entre una manzana y su sabor o peso), b) la diferencia entre un objeto y sus componentes (por ejemplo, entre una manzana y su piel o semillas) y c) la formación y distinción entre clases de objetos (por ejemplo, entre manzanas rojas, manzanas verdes, etc.) La idea de manejar objetos reales como contenedores de estados y comportamientos, es mucho más atractiva desde el punto de vista del usuario. De esta manera no tendrá que batallar con construcciones orientadas al computador, sino que podrá manejar objetos (y operaciones) que se asemejen más a sus equivalentes en el mundo real. La elevación del nivel de abstracción es sin duda un objetivo deseable. Las técnicas orientadas a objetos usan un mismo modelo conceptual para el análisis, el diseño y la programación. La transición desde el análisis al diseño es tan natural que es difícil especificar donde comienza uno y donde acaba el otro. Programas ejemplo. Ligaduras Dinámicas. Ventajas e inconvenientes de la orientación a objetos Entre las ventajas más importantes podemos destacar: Favorece la comunicación entre analistas, diseñadores, programadores y usuarios finales al utilizar todos los mismos modelos conceptuales. Esto se traduce en un aumento de la productividad, ya que la comunicación es uno de los puntos críticos en las primeras fases del proyecto. Se facilita la representación de estructuras complejas sin necesidad de adaptarnos a normas y modelos, ya que lo que manejamos son objetos del mundo real, lo que facilita la tarea del analista. La semántica de estas técnicas es más rica (al ser más natural); al usuario final le es más fácil comprender lo que el analista representa en sus modelos (ya que representa los objetos que lo rodean habitualmente) Favorece la modularidad, la reusabilidad y el mantenimiento del software. Estas técnicas son más resistentes al cambio que las tradicionales técnicas de análisis orientadas a flujos de datos. Algunas de sus desventajas: Hay que ser muy cuidadosos en la creación de los objetos, ya que de ello dependerá el éxito de nuestro proyecto. Un error en estas primeras definiciones podría resultar catastrófico. Precisamente el secreto de esta técnica está en la correcta definición inicial de los objetos. Los estándares en este tipo de técnicas están en continua evolución, lo que exige una actualización permanente. Los analistas, diseñadores y desarrolladores del proyecto deben conocer las reglas del juego y poseer suficiente experiencia en programación. El modelo OO Podemos indicar que se apoya en cuatro conceptos básicos: objeto clase herencia envío de mensajes Los primeros tres conceptos se refieren a la parte estructural o estática del modelo y el cuarto, que corresponde a mensajes, se refiere a la parte del comportamiento dinámico. Programas ejemplo. Ligaduras Dinámicas. Definiciones básicas Definición de Objeto: En términos más generales, un objeto es una abstracción conceptual del mundo real que se puede traducir a un lenguaje computacional o de programación OO. La abstracción de objeto se caracteriza por tener una identidad única que lo distingue de otros objetos. También tiene un estado, que permite informar lo que éste representa y su comportamiento, es decir lo que él sabe hacer. Hablando en términos computacionales, la identidad del objeto se puede interpretar como la referencia. El estado de objeto es una lista de variables conocidas como sus atributos, cuyos valores representan el estado que caracteriza al objeto. El comportamiento es una lista de métodos, procedimientos, funciones u operaciones que un objeto puede ejecutar a solicitud de otros objetos. Los objetos también se conocen como instancias. Definición de Clase: Es una colección de objetos similares. Estos objetos deben tener los mismos atributos con valores posiblemente diferentes asignados a estos, y el mismo conjunto de métodos que definen su comportamiento. Por otro lado también se puede ver una clase como un molde, esquema o un patrón que define la forma de sus objetos. O bien, como la estructura estática que define: a) el esquema de estados, y b) el comportamiento que van a tener los objetos A partir de ese esquema, dinámicamente durante la ejecución de un programa, se van a ir creando objetos que pertenezcan a esa clase. Definición de Herencia: Una clase puede heredar sus atributos y métodos a varias subclases (la clase que hereda es llamada superclase). Esto significa que una subclase, aparte de los atributos y métodos propios, tiene incorporados los atributos y métodos heredados de la superclase. Una subclase puede a su vez comportarse como una superclase y heredar a otras clases, creando de esta manera la jerarquía de herencia. Cuando una clase hereda de más de una superclase se conoce como herencia múltiple. Definición de Envío de Mensajes: ¿Qué sucede cuando los objetos desean comunicarse entre sí?. Un objeto recibe un estímulo externo de solicitud de un servicio que se traduce en la invocación de un método de éste objeto. Al ejecutarse el método, el objeto puede solicitar servicios de otros objetos, enviándoles mensajes que implican a su vez la invocación de sus métodos, y dentro de estos, nuevamente invocar servicios de otros objetos y así sucesivamente. Este envío de mensajes en cascada representa el comportamiento dinámico del modelo de objetos. Programas ejemplo. Ligaduras Dinámicas. Haciendo un paréntesis, es importante diferenciar entre lenguajes OO y lenguajes que no lo son. Tenemos lenguajes: Base-objetos: Lenguajes que no tienen herencia. Presentan un concepto parecido a clase y alguna forma de crear objetos a partir de ésta. Orientado a objetos: Presentan el concepto de objetos, clases y herencia de clases. Diferencia entre el modelado por descomposición funcional y el OO. Veamos la diferencia con un ejemplo Problema: Hacer bife criollo Resolución según la Descomposición funcional: Se declara una lista de datos, los cuales se encuentran en un espacio común. El algoritmo divide al problema en sub-problemas o funciones, partiendo de las más complejas hasta llegar a las acciones más sencillas de realizar, llamadas también atómicas. En todo momento la descomposición del problema se hará identificando las acciones (verbos) que se deben realizar. Hacer bife criollo acompañado de papa se divide en dos subproblemas: freír bifes con cebollas añadir acompañamiento Freír bifes con cebollas presenta tres subdivisiones: freír bifes preparar salsa con cebolla, perejil y pimientos verdes juntar bifes con la salsa Freír bifes y juntar bifes con la salsa son actividades que ya se saben realizar (atómicas). Sin embargo, el caso de preparar salsa con pimientos verdes aún podemos aclararlo más: Rehogar cebolla, el pimiento verde y el perejil Agregar 1 ajo picado chico freír la salsa que ya son actividades atómicas. Programas ejemplo. Ligaduras Dinámicas. Para el caso de añadir acompañamiento se particiona en dos actividades atómicas añadir papa cocida añadir perejil Si se deseara ahora preparar bife criollo con salsa de pimiento rojo, se tendría que buscar cuales actividades hay que modificar. En este caso sería la parte de los datos y preparar salsa verde, rehogar cebolla pimiento verde y perejil, en el caso de nuestro ejemplo. Sin embargo, lo complicado no termina en modificarlos, ya que no se sabe si en alguna otra parte del sistema se puedan referenciar y entonces esto traiga problemas. Descomposición OO La modelación de esta solución se realiza a través de los sustantivos que definen al problema. En este caso los sustantivos (nombres) más importantes son: Bife_Criollo, Salsa_Verde, Ingredientes, Licuadora, Sartén y Acompañamiento. Todos estos van a ser nuestros objetos que internamente van a integrar datos y operaciones, que podemos asociarlos de manera lógica a cada uno de sus conceptos. Cuando se pide haz_bife_criollo al objeto Bife_Criollo, este debe tener un método que sabe hacer bife criollo apoyándose en el objeto Freír_Bifes_Con_Cebolla, que tiene bifes como dato y saber freír bifes cómo método. Para el caso de Salsa de pimiento verde, Bife_Criollo le envía un mensaje diciéndole prepárate y entonces se preparará enviando mensajes a Ingredientes que los Rehoga, Licuadora que los pica y finalmente llama a Sartén para que los fría. Finalmente Bife_Criollo le va a enviar un mensaje a Acompañamiento, para que se añada la papa y el perejil, y quede finalmente preparado nuestro plato Bife Criollo. Es importante notar que los datos se encuentran implícitos formando parte de los objetos. Si en este modelo se desea hacer el Bife Criollo con Salsa de Pimientos Rojos, solo bastaría sustituir el objeto Salsa de Pimientos Verdes por el objeto Salsa de Pimientos Rojos, que se preparará, enviando mensajes a Ingredientes, Licuadora y Sartén, sin modificar nada más.