Clase del 18/09/2007 (Diseño Avanzado con Objetos)

De Cuba-Wiki
Revisión del 20:44 4 nov 2007 de 201.235.160.180 (discusión)
(difs.) ← Revisión anterior | Revisión actual (difs.) | Revisión siguiente → (difs.)

DESIGNING REUSABLE CLASSES (JOHNSSON-FOOTE)

La Programación Orientada a Objetos promueve el reuso. Se reduce el tiempo de desarrollo y el costo de mantenimiento de los sistemas. Pero esto no es gratis, hay que trabajar para eso. Hay técnicas para producir componentes reusables.

Un objeto es similar a un valor de un TAD, en el sentido en que ambos encapsulan datos y operaciones sobre esos datos (sic). Por esto, los lenguajes orientados a objetos proveen modularidad y ocultamiento de información (information hiding). Pero hay dos ventajas clave que se agregan en la orientación a objetos: polimorfismo y herencia.

Polimorfismo Los objetos solo saben responder mensajes. Cuando se le envía un mensaje a un objeto, este mensaje se asocia con un método que se va a ejecutar para responder a ese mensaje. Pero esta asociación se hace en el momento de recepción del mensaje y no antes (late-binding). El método que asociado depende de cual es la clase de la que es instancia el objeto receptor. Pues allí esta definido este. El ejemplo típico es un grupo de elementos en un Array, cada uno de los cuales puede pertenecer a una clase distinta. En tanto todos los elementos entiendan los mensajes que se les mandan, otro objeto puede interactuar con el contenido del array sin preocuparse por la clase de los elementos.

Protocolo La especificación de un objeto esta dada por su protocolo, es decis, los conjunto de mensajes a los que sabe responder. El tipo de los argumentos también es importante, pero es importante referirse al “tipo” como el protocolo y no la clase. Objetos con protocolos idénticos son intercambiables. Es por est que la interface entre los objetos está definida por el protocolo que cada una de ellas espera que la otra sepa entender. Los protocolos ademas de ser importante por definir las interfaces en los programas, ellos son aún más importantes como medio de comunicación entre los programadores. Los protocolos compartidos crean un vocabulario que los programadores pueden reutilizar para facilitar el aprendizaje de nuevas clases. Así como los matemáticos reutilizan los nombres de las operaciones para matrices, polinomios, y otros objetos algebraicos, de la misma manera los programadores de smalltalk usan los mismos nombres para las operacions en muchos clases. De esta manera, un programador sabrá el significado de muchos componentes de un nuevo programa la primera vez que lo leen. La utilización de protocolos estándares favorece el polimorfismo.

Herencia La herencia tiene algunas ventajas: en principio promueve el reuso de código y provee de un modo de organizar y clasificar las clases, ya que clases con la misma superclase suelen estar bastante relacionadas. Otra ventaja es que la herencia promueve el desarrollo de protocolos estándares. También permite la extensión de clases existentes dejando el código existente intacto. De esta manera los cambios hechos por un programador difícilmente afecten a otro.


Clases Abstractas Comúnmente los protocolos estándares se representan en clases abstractas. Por lo general, conviene subclasificar de una clase abstracta, ya que una clase concreta tiene definido que colaboradores internos conforman su estado, es decir, como estarán representadas sus instancias, y es común que algunas subclases puedan necesitar una representación diferente. Por otro lado, las clases abstractas no necesitan tener colaboradores internos definidos ya que estas pueden estar definidas en sus sublases según la conveniencia de cada una de ellas. Esto evita estos conflictos.

Toolkits y Frameworks. Los frameworks son diseños reutilizables, comúnmente formados por varias clases abstractas y algunas clases concretas de componentes que se pueden reutilizar. Definen la arquitectura de la aplicación (o parte de ella). Los Toolkits, en cambio, son independientes de la aplicación, pueden ser reutilizados en dominios totalmente diferentes y no definen la arquitectura. La principal diferencia entre ambos es que en los frameworks hay inversión de control. Es decir, el usuario del framwork define objetos con los que el framework colabora. Algo que claramente no sucede en Collection por ejemplo. Por otro lado, los framworks pueden verse como algo concreto freente a los patrones de diseños ya que son diseños implementados y no ideas abstractas.

While-Box vs Black Box Frameworks.

White-Box: El usuario debe subclasificar de clases abstractas. Por lo tanto, esto requiere que conozca como el framwork está construido. Esto puede resultar difícil de aprender a usar para un nuevo usuario. Black-Box: A diferencia del caso anterior, a este tipo de frameworks se le provee con componentes con comportamientos específicos de la aplicación. Estos componentes deben respetar ciertos protocolos. El framework también provee de muchos componentes. El usuario solo necesita conocer y entender las interfaces externas para utilizarlo. En general son más fáciles usar pero menos flexibles.


Ciclo de Vida. Crear clases abstractas y frameworks es una forma de hacer componentes reutilizables y un modo de limpiar el diseño. Dado que los White-Box frameworks son una convención de redefinición de métodos, no hay una línea fina entre lo que es un White-Box framework y una simple jerarquía de clases. Por lo general es difícil encontrar clases abstractas al principio. El humano piensa mejor sobre ejemplos concretos para luego generalizar. Por eso es común que se encuentren más y mejores abstracciones a medida que el dominio se va conociendo con más detalle.


Reglas para encontrar protocolos estándares. 1) Introducción de recursión: si un objeto receptor de un mensaje X, al ejecutar el metodo correspondiente realiza operaciones similares sobre sus colaboradores, entonces los mensajes a los colaboradores tambien deberían llamarse X (aún cuando la cantidad de parámetros no coincida). De esta manera el lector del programa notará la conexión. Aún cundo no haya realmente recursión, el método parecerá recursivo.

2) Eliminar los Case análisis. 3) Reducir el número de argumentos. 4) Reducir el tamaño de los métodos: es más facil subclasificar y redefinir métodos pequeños que redefinir uno muy grande que haga muchas cosas. Por lo general, de esta manera todos los métodos heredados son correctos pero una parte debería ser cambiada en lugar de tener que redefinir todo el método grande.

Reglas para encontrar clases abstractas 5) Jerarquias profundas y angostas. 6) El tope de una jerarquía debería ser abstracto. 7) Minimizar acceso a variables: de esta manera las clases se hacen más abstractas eliminando su dependencia con la representación concreta. Una forma de hacerlo es acceder a los colaboradores internos mediante mensajes. 8) Las subclases deben ser especialización.

Reglas para encontrar frameworks. 9) dividir clases grandes en más pequeñas. 10) Factorizar las diferencias de implementaciones en subcomponentes (?). 11) Separar Métodos que no se comunican en diferentes clases. 12) Enviar mensajes a componentes en lugar de a self: un framework basado en herencia puede ser convertido en uno basado en componentes reemplazando métodos sobrescritos con mensajes a componentes. 13) Reducir el número de parámetros implícitos: A veces es difícil dividir una clase en dos o más porque los métodos que deben ir en diferentes clases acceden a las mismas variables de instancia.