|
Programación Orientada a Objeto |
Introducción
Las ideas
básicas de la orientación a objetos nacen a principios de los años 60 en
la Universidad de Noruega. Un equipo dirigido por el Dr. Nygaard se
dedicaba a desarrollar sistemas informáticos para realizar simulaciones de
sistemas físicos. La dificultad en la que se encontraba era doble. Por un
lado los programas eran muy complejos y, por otro, forzosamente tenían que
ser modificados. Este segundo punto era especialmente problemático, ya que
la razón de ser de los programas era el cambio y no solo se requerían
varias iteraciones para obtener un producto con el rendimiento deseado,
sino que muchas veces se quería obtener diversas alternativas viables cada
una con sus ventajas e inconvenientes. La solución que idearon fue diseñar
el programa paralelamente al objeto físico, es decir, si el objeto físico
tenía cien componentes, el programa tendría cien módulos, uno por
componente. De esta forma, habría una correspondencia entre el sistema
físico y el informático. Este enfoque
resolvió los dos problemas planteados. Primeramente, ofrecía una forma
natural de partir un programa muy complejo y, en segundo lugar, el
mantenimiento pasaba a ser controlable. El primer punto es obvio ya que, a
partir el programa en unidades informáticas paralelas a las físicas, la
descomposición era automática. El segundo punto también se resuelve ya
que, a cada iteración de simulación, el analista querrá cambiar o bien
piezas enteras o bien el comportamiento de alguna pieza. En ambos casos la
localización de los cambios está perfectamente clara y su alcance se
reduce a un componente. Pero, poco a
poco, fue obteniéndose otro beneficio muy importante, que es la razón
principal por la que la industria informática se ha abocado a la
orientación a objetos. Se trata de la reusabilidad. En el proceso de
construcción de un programa se obtienen piezas para futuros programas.
Para dar soporte a estas ideas lo que se hizo fue crear un lenguaje para
darle soporte, Simula-67, que continua utilizándose actualmente. El siguiente
paso se da en los años 70 en los Estados Unidos. Xerox tiene un centro de
investigación en Palo Alto, donde trabajan en conceptos que puedan
convertirse en productos industriales al cabo de 12 a 20 años. Así pues,
en aquellos años contrataron a un joven llamado Alan Kay para que llevase
a término las ideas que proponía en su tesis doctoral, la propuesta de
construcción de un ordenador llamado Dynabook, adecuado para ser utilizado
por niños. El ordenador no tenía teclado, la pantalla era sensible al
tacto y la mayor parte de la comunicación era gráfica. Al desarrollar este
proyecto se invento el Mouse y los entornos gráficos. Al volver a
encontrarse con una programación compleja y experimental, como en el caso
de Nygaard, decidieron crear un entorno y lenguaje llamado Smalltalk. Smalltalk
tuvo una gran difusión y cuando en los años 80 en ATT-Bell quisieron crear
un sucesor al lenguaje C, incorporaron las principales ideas de Smalltalk
y Simula, creando el lenguaje C++. Este
desarrollo que se ha descrito se refiere sólo a la evolución que ha tenido
la orientación a objetos en el mundo de la ingeniería del software. Ha
existido un desarrollo paralelo de los mismo conceptos en el mundo de la
inteligencia artificial, donde el lenguaje CLOS, una variante de Lisp
orientada a objetos, está muy extendido. Términos y Conceptos de la POO. Muchos de
los términos y definiciones
empleadas en la Programación OO no son definitivos, es decir, puede variar
dependiendo de con quien hablemos. Esto es normal, ya que por ejemplo, en
España, dependiendo de en que comunidad estemos, hay palabras que aun
teniendo el mismo significado (o identificando el mismo concepto), se
pronuncian de distinta manera. Objetos. Los Objetos
son cosas físicas que se encuentran alrededor de nosotros. Hardware,
software, documentos, casas, coches son todos ejemplos de objetos. Los
objetos que podría ver un ejecutivo son: mesas, empleados, documentos, ..
Un ingeniero mecánico podría ver aceites, ruedas, medidores de nivel,
.. Los objetos
son cosas que tienen un estado. El estado de un objeto es la condición de
un objeto o el conjunto de circunstancias que describen a un objeto. Es
común hablar de estado de información de un objeto, por ejemplo, el estado
de información de un reloj es su hora actual, el estado de información de
una lámpara puede ser apagada o encendida. Hacer una descripción exacta de
los estados de objetos complejos puede resultar muy difícil, pero
afortunadamente, cuando usamos objetos para modelar el mundo real o para
imaginar situaciones, restringimos los posibles estados de los objetos y
nos quedamos con aquellos estados relevantes a nuestro modelo.
Muchos de
los objetos son estáticos, esto es, el estado de un objeto no cambia a
menos que algo externo al objeto se lo requiera. Esto es lo común. Sin
embargo, para algunos objetos es posible cambiar su propio estado. Si un
objeto es capaz de cambiar su propio estado espontáneamente, se dice que
ese objeto es un objeto con vida, también llamados objetos activos o
actores. Un ejemplo de objeto con vida, podría ser un reloj. Si estamos
modelando un proceso de negocios, podríamos considerar a los vendedores y
comerciantes como objetos con vida. Clases. Hay dos
grandes categorías de objetos: clases e instancias. Los usuarios de la POO
piensan en las clases como contenedores de la información necesaria para
crear instancias, estos son, la estructura y las capacidades de una
instancia están determinadas por su correspondiente clase. Hay tres
definiciones válidas de clase:
Superclases. Una
superclase es una clase cuyas instancias también son clases. Esto
significa que cuando se use el mecanismo de creación de instancias en una
metaclase, la instancia creada será una clase. Un concepto
muy similar al de metaclase es el de clase parametrizada. Una clase
parametrizada es una plantilla para una clase, es decir, una clase se crea
rellenando la plantilla con los datos específicos de esa clase Nosotros
usaremos el termino de clase y haremos la distinción solo cuando sea
necesario. Una definición que también usaremos es la de instanciación que
tiene dos significados: ·
como verbo, instanciación es
el proceso de creación de la instancia de una clase, y ·
como nombre, una
instanciación es una instancia de una clase. Quienes
adoptan la tecnología orientada a objetos suelen abrazar estas prácticas
por una de dos razones. Primero, buscan una ventaja en la competitividad,
como un tiempo reducido para la comercialización, mayor flexibilidad de
los productos o fiabilidad en la planificación. Segundo, pueden tener
problemas que sean tan complejos que parezcan no tener ninguna otra
solución. El uso del
modelo de objetos conduce a construir sistemas que incorporan los cinco
atributos de los sistemas complejos bien estructurados: El modelo de
objetos forma el marco de referencia conceptual para la notación y el
proceso del desarrollo orientado a objetos, y así el propio método se
beneficia de estas ventajas. Algunas de ellas son: ·
Explota la potencia
expresiva de todos los lenguajes de programación orientados a
objetos. ·
Alienta la reutilización de
componentes del software. ·
Lleva a sistemas más
flexibles al cambio ·
Reduce el riesgo de
desarrollo ·
Resulta atractivo al
funcionamiento de la mente humana. Hay una
serie de casos de estudio que apoyan estos hallazgos: en particular,
apuntan que el enfoque orientado a objetos puede reducir el tiempo de
desarrollo y el tamaño del código fuente resultante. En el lado
más oscuro del diseño orientado a objetos, se encuentran dos áreas de
riesgo que deben ser consideradas: eficacia y costes de puesta en
marcha. En relación
con los lenguajes procedimentales, definitivamente existe un coste de
eficacia por enviar un mensaje de un objeto a otro en un lenguaje de
programación orientado objetos. Para invocaciones de métodos que no pueden
resolverse estáticamente, una implantación debe realizar una búsqueda
dinámica con el fin de encontrar el método definido por la clase del
objeto receptor. Los estudios indican que, en el peor caso, una invocación
de método para llevar de 1,75 a 2,5 veces el tiempo de una simple llamada
a subprograma. En el lado positivo, centrémonos en la frase operativa, "no
puede resolverse estáticamente". La experiencia indica que se necesita
realmente búsqueda dinámica sólo en aproximadamente el 20 por ciento de la
mayoría de las invocaciones a métodos. Con un lenguaje con comprobación
estricta de tipos, un compilador puede frecuentemente determinar qué
invocaciones pueden resolverse estáticamente y generar código para
llamadas a subprograma en vez de para búsqueda de método. Otra fuente
de sobrecarga para la ejecución proviene no tanto de la naturaleza de los
lenguajes de programación orientados a objetos, sino de la forma en que se
los utiliza en conjunción con el desarrollo orientado a objetos. Como ya
se ha dicho muchas veces, el desarrollo orientado a objetos lleva a crear
sistemas cuyos componentes están construidos en capas de abstracción. Una
implicación de esta división en capas es que los métodos individuales son
generalmente muy pequeños, ya que se construyen sobre otros de nivel
inferior. Otra
implicación es que a veces hay que escribir métodos para conseguir un
acceso protegido a los campos (de otro modo encapsulados) de un objeto.
Este montón de métodos significa que se puede acabar con una saturación de
invocaciones de métodos. La invocación de un método a un nivel alto de
abstracción suele resultar en una cascada de llamadas a métodos; los
métodos de alto nivel suelen llamar a otros de nivel inferior, y así
sucesivamente. Para aplicaciones en las que el tiempo es un recurso
limitado, tantas invocaciones a métodos pueden ser inaceptables. De nuevo
desde el lado positivo, tal división en capas es esencial para la
comprensión de un sistema; puede que no llegue nunca a ser posible tener
un sistema complejo funcionando si no se empieza por un diseño en capas.
Se recomienda diseñar primero por funcionalidad, e instrumentar después el
sistema en funcionamiento para determinar dónde hay realmente cuellos de
botella en la velocidad. Estos cuellos de botella pueden eliminarse muchas
veces declarando los métodos apropiados como inline (intercambiando por
tanto espacio por tiempo), reduciendo la jerarquía de clases o rompiendo
el encapsulamiento de los atributos de una clase.
Un riesgo de
eficacia relacionado se deriva de la sobrecarga de las clases: una clase
profunda en una trama de herencias puede tener muchas superclases, cuyo
código hay que incluir en la clase más específica al montar los enlaces
(linking). Para aplicaciones orientadas a objetos pequeñas, esto puede
significar en la práctica que las jerarquías de clases profundas deben
evitarse, porque requieren demasiado código objeto. Este problema puede
mitigarse un poco utilizando un compilador y un montador de enlaces
experto que puedan eliminar todo el código muerto.
Hay aún otra
fuente de cuellos de botella para la eficacia en el contexto de los
lenguajes de programación orientados a objetos, que se deriva del
comportamiento paginado de las aplicaciones en ejecución. La mayoría de
los compiladores ubican el código objeto en segmentos, con el código de
cada unidad de compilación (con frecuencia un solo archivo) situado en uno
o más segmentos. Este modelo supone una alta localidad de la referencia;
los subprogramas dentro de un segmento llaman a subprogramas del mismo
segmento. Sin embargo, en sistemas orientados a objetos, raramente se da
esa localidad de la referencia. Para sistemas mayores, las clases suelen
declararse en archivos separados, y puesto que los métodos de una clase se
construyen usualmente sobre los de otras clases, una sola invocación de
método puede involucrar código de muchos segmentos. Esto viola las
suposiciones que la mayoría de los computadores realizan sobre el
comportamiento de los programas en tiempo de ejecución, particularmente
los computadores con CPUs en tubería y sistemas de memoria por paginación.
Volviendo al lado positivo, ésta es la razón por la que se separan las
decisiones de diseño lógicas y físicas. Si un sistema en funcionamiento se
ralentiza durante la ejecución debido a un intercambio de páginas
excesivo, el acotar el problema es en gran medida cuestión de cambiar la
asignación física de las clases a módulos. Esta es una decisión de diseño
del modelo físico del sistema, que no tiene efecto sobre su diseño
lógico. Otro riesgo
de eficacia en sistemas orientados a objetos proviene de la asignación y
destrucción dinámica de objetos. Asignar memoria a un objeto en el heap
(montón) es una acción dinámica, en oposición con la ubicación estática de
un objeto, ya sea globalmente o en un marco de pila, y la ubicación en el
heap suele costar más recursos de computación. En muchos tipos de sistema,
heap suele costar más recursos de computación. En muchos tipos de sistema,
esta propiedad no causa ningún problema real, pero en aplicaciones
críticas respecto al tiempo, no pueden admitirse los ciclos que se
necesitan para completar una asignación del heap. Hay soluciones simples
para este problema: o bien preasignar espacio a tales objetos durante la
elaboración del programa, en vez de asignarlo durante la ejecución de
algún algoritmo crítico respecto al tiempo, o bien reemplazar el gestor de
memoria del sistema por defecto por uno afinado para el comportamiento de
este sistema específico. Otra nota
positiva: ciertas propiedades de los sistemas orientados a objetos a
menudo ensombrecen todas las fuentes de problemas de eficacia. Por
ejemplo, Russo y Kaplan relatan que el tiempo de ejecución de un programa
en C ++ es en muchas ocasiones más rápido que el de su equivalente
funcional en C. Ellos atribuyen esta diferencia al uso de funciones
virtuales, que eliminan la necesidad de algunas formas de comprobación
explícita de tipos y de algunas estructuras de control. En realidad, en
nuestra experiencia, los tamaños del código de sistemas orientados a
objetos suelen ser menores que sus implantaciones no orientadas a objetos
funcionalmente equivalentes. En algunos
proyectos, los costes de puesta en marcha asociados con el desarrollo
orientado a objetos pueden manifestarse como una barrera muy real para la
adopción de esta tecnología. El uso de cualquier tecnología tan novedosa
como esta requiere la capitalización de las herramientas de desarrollo del
software. Además, si una organización de desarrollo está utilizando un
lenguaje de programación orientada a objetos por primera vez, en general
no tendrá una base establecida de software específico de la aplicación
para reutilizar. En resumen, tienen que partir desde cero o al menos
pensar como conectar sus aplicaciones orientadas a objetos con otras no
orientadas a objetos ya existentes. Por último, un primer intento de usar
desarrollo orientado a objetos seguramente fallará sin el entrenamiento
apropiado. Un lenguaje de programación orientado a objeto no es " sólo
otro lenguaje de programación " que puede aprenderse en un curso de tres
días o leyendo un libro. Como se ha puesto de relieve, lleva un tiempo
desarrollar la mentalidad adecuada para el diseño orientado a objetos, y
esta nueva forma de pensar deben abrazarla tanto los desarrolladores como
sus gestores. Lenguajes Orientados a Objetos. Ha surgido
una gran variedad de lenguajes orientados a objetos, a continuación
veremos brevemente algunos de ellos: Lenguaje
C++ El C++, se
diseño como un sucesor del lenguaje C, y no todas las innovaciones que se
introdujeron tienen que ver con la programación orientada a objetos. Así,
algunos de los cambios fueron las funciones en línea, los prototipos de
funciones, los modificadores const y volatile, los argumentos optativos y
por omisión sobre funciones, la palabra clave void, la entrada y salida
basada en listas infinitas y las especificaciones de ligadura. El manual de
consulta obligatorio para el lenguaje es el libro escrito por el creador
de C++, Bjarne Strostrup. Lamentablemente, como es común con los lenguajes
de programación, el lenguaje evolucionó una vez que comenzó a usar el
sistema un grupo grande de programadores y de esta manera quedó algo
atrasado el libro original. Hay docenas
de guías de instrucción de C++. Entre las más populares están las de
Lippman, Wiener, Hansen, Chirlian, Eckel... Objective-C La
descripción más accesible de los principios de Objective-C es el libro del
creador del lenguaje, Brad Cox (1986). Lamentablemente, como es el caso
del texto análogo de C++, el lenguaje ha cambiado mucho desde la
publicación del libro original. Una cantidad de información un tanto más
actual se da en el Webster, que es una introducción general al entorno de
programación NeXT. Existe información adicional disponible en línea dentro
del sistema NeXT. Este lenguaje permite el acceso directo del usuario a
los mecanismos subyacentes de mensajes, lo cual, a veces puede ser
útil para optimizar secciones de código que se usan de forma intensiva.
Sin embargo los detalles de
la implantación son demasiado específicos. Smalltalk La
descripción definitiva de Smalltalk-80, el sistema estándar de Smalltalk,
es el libro de Goldberg y Robson. Se le conoce familiarmente como el libro
azul, y es parte de una serie de libros sobre este lenguaje. El libro azul
cubre tanto el lenguaje como la parte de descripción de implantación.
Entre los demás libros de la serie hay uno sobre el entorno de
programación interactivo (Goldberg 83), uno acerca de la
historia de los diferentes aspectos de implantación original de
Smalltalk (Krasner 83), y una versión condensada del libro azul que trata
solo el lenguaje (Goldberg 89). Otros libros
interesantes sobre el lenguaje son el de Kaehler y Patterson, el de Budd,
el de Wiener... Object
Pascal Este
lenguaje fue desarrollado por Apple Computer con la asesoría del diseñador
de Pascal, Niklaus Wirth; se basó parcialmente en una ampliación anterior
de Pascal, desarrollada por Apple, llamada Classical. El lenguaje se
define en un informe de Apple (Tesler 85). El sistema
QuickPascal de MICROSOFT es una implantación del sistema Object
Pascal. El lenguaje QuickPascal se describe en (Shammas 90). Una
aplicación amplia de Object-Pascal se presenta en (Schmucker 86), que
también describe Classical y diversos lenguajes orientados a objetos. Turbo
Pascal Es una
versión orientada a objetos de Pascal. El manual de consulta es Turbo
88 aunque existe una gran cantidad de ellos. Todos los textos tienen un
inconveniente y es que primero presentan la programación Pascal, y más
tarde introducen las extensiones orientada a objetos como tan solo una
adición, o una ocurrencia tardía; de esta manera se podría hacer creer al
lector que las extensiones orientadas a objetos son tan solo una adición
para programar en modo convencional en lugar de una técnica que requiere
un completo replanteamiento del proceso de diseño. A pesar de
las similitudes en nombre y sintaxis, Turbo Pascal es muy diferente a
Object Pascal. Turbo Pascal toma ideas de C++ como la de los constructores
y la distinción entre métodos estáticos y virtuales. Otros
Lenguajes La mayoría
de los conceptos asociados con la programación orientada a objetos se
desarrollaron primero en el lenguaje de programación Simula. Por
desgracia, en EE UU, este lenguaje fue visto nada más que como una
extensión del Algol orientada en forma específica hacia la simulación, y
por ello se le prestó relativamente poca atención. Posteriormente fueron
surgiendo otros como Eiffel diseñado específicamente con principios
modernos de ingeniería del software y con características como capacidad
para agregar afirmaciones, que se revisan en tiempo de ejecución, a clases
y métodos individuales. Ha sido utilizado en muchos proyectos de software
comercial. Otro
lenguaje orientado a objetos es el Actor, basado en el Pascal.
Pero sobre
todo la tendencia ha sido versiones de los lenguajes ya existentes, ya sea
el LOGO, LISP... aplicando los diferentes conceptos que caracterizan el
diseño de objetos. Más
recientemente y con el auge de las comunicaciones vía Internet, a tomado
una importancia relevante, JAVA. Selección de un Lenguaje Orientado a Objetos Dada la gran
cantidad de lenguajes orientados a objetos existentes, es fácil que el
programador no realice una correcta elección de la que más le conviene.
Esta exposición supone un breve índice de puntos a tener en cuenta para
dicha elección. 1.
Familiaridad: Este punto se
refiere a la elección de un lenguaje orientado a objetos cuya versión
convencional conozcamos. No siempre es fácil pasar de una a la otra, esto
hay que tenerlo en cuenta. 2.
Plataformas: No todos los
lenguajes se ejecutan en todas las plataformas Hardware aunque este
inconveniente cada vez es menor dada la tendencia del mercado hacia el
PC. 3.
Importancia del tiempo de
programación en relación con el tiempo de ejecución: Hay lenguajes
como el C++, orientados hacia una optima ejecución y otros como el
Smalltalk buscan la facilidad para el desarrollo de los programas. 4.
Ubicuidad: Los lenguajes
populares, tendrán más cantidad de manuales, herramientas... lo cual
supone una ventaja. 5.
Acceso a código
existente: La existencia de
bibliotecas puede acortar considerablemente el tiempo de desarrollo de una
aplicación. 6.
Entornos de
programación: La disponibilidad de
editores, depuradores y otras herramientas simplifica la creación de
nuevas aplicaciones. 7.
Características de
entrega: En los lenguajes
interpretados el entorno de programación se necesita junto con el
programa ejecutable, por ejemplo el SMALLTALK, no así otros lenguajes como
C++ que generan un archivo convencional ejecutable en binario. |