+ All Categories
Home > Documents > Capitulo 3 - Jerarquía Collection

Capitulo 3 - Jerarquía Collection

Date post: 03-Jul-2015
Category:
Upload: jose-ben-hur-saravia
View: 153 times
Download: 5 times
Share this document with a friend
Popular Tags:
18
Capitulo 3 Jerarquía de Collection La jerarquía de Collection es una de las más importantes dentro de un ambiente vivo de objetos pensado para generar modelos computacionales. Esto se debe a que en la gran mayoría de los dominios existen entes de la realidad que son o contienen colecciones de otros entes. Dado esto, es muy importante contar en el ambiente con colecciones de diferentes características: con o sin orden, con elementos únicos o repetidos, de tamaño fijo o variable. A su vez el modelo que implemente estas colecciones debe ser flexible, extendible y performeante. Esta última característica es muy importante, ya que afectará la performance de otros modelos creados dentro del ambiente. En capítulos anteriores se mencionó que la nueva jerarquía implementada estaría acotada por las clases definidas por el ANSI, así como también, por los protocolos especificados para cada una de estas. Esta decisión se tomo porque se debía acotar el dominio de las colecciones, ya que el mismo es muy amplio y puede haber diferentes interpretaciones de cuáles son las colecciones a implementar y sobre cuál es su comportamiento. Este capítulo describe, en primer lugar, la jerarquía de protocolos definida por el ANSI para las clases concretas que el mismo documento especifica. A partir de estas definiciones queda acotado el dominio modelado en este trabajo. Una vez definido el dominio, se realiza una descripción de la jerarquía implementada en Squeak. Además se analizan los principales problemas que presenta esta implementación de la jerarquía de Collection. Con el fin de dar un primer acercamiento al nuevo modelo generado, al finalizar este capítulo se presenta la nueva jerarquía de
Transcript
Page 1: Capitulo 3 - Jerarquía Collection

Capitulo 3

Jerarquía de CollectionLa jerarquía de Collection es una de las más importantes dentro de un ambiente vivo de objetos pensado para generar modelos computacionales. Esto se debe a que en la gran mayoría de los dominios existen entes de la realidad que son o contienen colecciones de otros entes.

Dado esto, es muy importante contar en el ambiente con colecciones de diferentes características: con o sin orden, con elementos únicos o repetidos, de tamaño fijo o variable. A su vez el modelo que implemente estas colecciones debe ser flexible, extendible y performeante. Esta última característica es muy importante, ya que afectará la performance de otros modelos creados dentro del ambiente.

En capítulos anteriores se mencionó que la nueva jerarquía implementada estaría acotada por las clases definidas por el ANSI, así como también, por los protocolos especificados para cada una de estas. Esta decisión se tomo porque se debía acotar el dominio de las colecciones, ya que el mismo es muy amplio y puede haber diferentes interpretaciones de cuáles son las colecciones a implementar y sobre cuál es su comportamiento.

Este capítulo describe, en primer lugar, la jerarquía de protocolos definida por el ANSI para las clases concretas que el mismo documento especifica. A partir de estas definiciones queda acotado el dominio modelado en este trabajo.

Una vez definido el dominio, se realiza una descripción de la jerarquía implementada en Squeak. Además se analizan los principales problemas que presenta esta implementación de la jerarquía de Collection.

Con el fin de dar un primer acercamiento al nuevo modelo generado, al finalizar este capítulo se presenta la nueva jerarquía de clases implementada para modelar las colecciones especificadas por el ANSI.

Jerarquía de Collection en el ANSISegún se describe en el documento ANSI de Smalltalk, el standard debía cumplir tres objetivos principales:

basándose sólo en el ANSI se debía poder implementar un Smalltalk,

los programas Smalltalk que cumplan con la especificación debían tener la misma semántica en cualquier implementación del lenguaje generada,

la especificación debía ser lo suficientemente completa para permitir crear programas Smalltalk útiles.

Page 2: Capitulo 3 - Jerarquía Collection

Si bien no existe descripción alguna sobre interfaces de usuario o sobre algún framework de base de datos, el documento es bastante consistente respecto a sus objetivos.

Un caso en donde se ve demostrado es en la jerarquía de Collection. Para esta jerarquía, el documento dedica una extensa sección donde define las colecciones concretas que todo Smalltalk debe tener implementado.

Para especificar el comportamiento de cada una de las colecciones concretas, la especificación define una jerarquía de protocolos abstractos. Estos protocolos están agrupados por las características esenciales de cada una de las colecciones. En la Figura 3.1 se puede ver la jerarquía completa que define el ANSI para las colecciones. Cabe aclarar que no todas ellas entran en el alcance de este trabajo, esto se explicará en detalle en la última sección de este capítulo.

Figura 3.1: Protocolos de la jerarquía de Collection definidos por el ANSI.

El primer detalle que se debe tener en cuenta es que los protocolos de clases concretas con las que el ambiente debe contar comienzan con mayúsculas. El ANSI no exige que se implementen en clases el resto de los protocolos abstractos que define. No obstante, exige que las clases concretas implementen los protocolos con los que están relacionadas en el gráfico.

El primer protocolo que merece ser descripto es el de <collection>, ya que el mismo es común a todas las colecciones. En este protocolo se describen los mensajes para manipular y operar sobre una colección de objetos, ya sea individualmente o como un todo. A grandes rasgos se define comportamiento para operar sobre los elementos, convertir la colección a otro de los tipos definidos y para verificar su vacuidad.

Comenzando de izquierda a derecha, el siguiente protocolo abstracto es <abstractDictionary>. Este provee los mensajes para acceder, agregar, remover, e iterar sobre los elementos de una colección sin orden, cuyos elementos son accedidos utilizando una clave que se les asigna explícitamente.

Hay dos protocolos de clases concretas que deben implementar <abstractDictionary>, estos son: <Dictionary> e <IdentityDictionary>. El primero representa a las colecciones con las características de <abstractDictionary> donde la equivalencia de su clave se define enviando el mensaje #=. La

Page 3: Capitulo 3 - Jerarquía Collection

diferencia con el segundo protocolo radica en que la equivalencia es definida enviando el mensaje #==1. Ninguno de estos protocolos agrega comportamiento a estas colecciones.

El siguiente protocolo abstracto es <extensibleCollection>, este define comportamiento básico para agregar y eliminar elementos de una colección de tamaño variable.

Los protocolos para las clases concretas <Set> y <Bag> deben implementar el protocolo <extensibleCollection>. El primero de estos representa una colección de tamaño variable, sin orden entre sus elementos. Además, sus elementos no pueden ser accedidos individualmente a través de una clave externa, y de la misma manera que los conjuntos matemáticos, no pueden tener elementos repetidos. <Bag> es similar a <Set>, pero al contrario que este último permite elementos repetidos.

Continuando de izquierda a derecha se encuentra <sequencedContractibleCollection>, este protocolo define comportamiento para remover elementos de una colección ordenada de objetos, cuyos elementos puede ser accedidos usando una clave externa representada por un entero o índice2.

El siguiente protocolo abstracto es <sequencedReadableCollection>, el cual define comportamiento para leer colecciones ordenadas cuyos elementos pueden ser accedidos individualmente utilizando un índice. El mismo debe estar entre uno (1) y el número de elementos de la colección inclusive.

Utilizando el comportamiento definido en <collection>, <extensibleCollection>, <sequencedContractibleCollection> y <sequencedReadableCollection> se define el protocolo para la clase concreta <SortedCollection>. Esta clase representa una colección de objetos de tamaño variable, cuyos elementos están ordenados basados en un criterio de ordenamiento. Este criterio se define en un bloque que recibe el nombre sortBlock. Los elementos pueden ser agregados y removidos, y además, estos pueden ser accedidos individualmente mediante un índice.

Otro de los protocolos abstractos definidos por el ANSI es <sequencedCollection>, este provee comportamiento para escribir en una colección ordenada de objetos, cuyos elementos pueden ser accedidos mediante un índice.

La clase concreta <OrderedCollection> debe implementar el protocolo definido para sí misma y además debe responder a los mensajes definidos en los protocolos: <collection>, <extensibleCollection>, <sequencedContractibleCollection>, <sequencedReadableCollection> y <sequencedCollection>. Esta representa una colección ordenada de objetos, de tamaño variable. Al igual que en SortedCollection se pueden agregar, eliminar o insertar elementos. A su vez, estos pueden ser accedidos a través de un índice. La diferencia entre ambas colecciones radica en que el 1 El mensaje #== retorna un objeto del tipo Boolean indicando si ambos objetos son exactamente la misma instancia.

2 Un índice es una clave de búsqueda a través de la cual se puede acceder al elemento indicado por el valor del mismo.

Page 4: Capitulo 3 - Jerarquía Collection

orden en <OrderedCollection> está dado por el orden en que se agregan los elementos, estos siempre se agregan al final de la colección.

Otra de las clases concretas definidas por el ANSI es <Interval>. Además de implementar protocolo propio de un intervalo, esta clase debe proveer el comportamiento definido en <sequencedReadableCollection> y en <collection> (como todas las demás colecciones). Los intervalos representan colecciones cuyos elementos son números que forman una progresión aritmética.

Algunas de las clases concretas definidas por el ANSI bajo la jerarquía de Collection quedaron fuera del alcance del proyecto. Estas son: <Array>, <ByteArray>, <String> y <Symbol>. A continuación se describe el porqué de esta decisión.

Tanto Array como ByteArray quedaron fuera del alcance por cuestiones implementativas, ya que son clases bien conocidas por la Virtual Machine (VM). Es decir, que la VM conoce su estructura interna y por lo tanto utiliza esta información para realizar optimizaciones. Además, estas clases deben subclasificar de su superclase utilizando mensajes especiales y no todo su comportamiento es implementado a través de colaboraciones entre objetos.

En Squeak la clase Array subclasifica ArrayedCollection con un mensaje especial:

variableSubclass:instanceVariableNames:classVariableNames:poolDictionaries:category:

A diferencia del mensaje común utilizado para subclasificar, este es el mensaje estándar de inicialización para crear una nueva clase como una subclase de una clase existente (el receiver) en donde la subclase tiene variables de punteros indexables.

Al mismo tiempo, muchos de los métodos implementados en Array utilizan, por cuestiones de performance, primitivas en lugar de colaboraciones entre objetos. Por lo tanto, si se implementa esta clase sin utilizar primitivas la performance se degradará notablemente. En caso de decidir implementarla haciendo uso de las primitivas, prácticamente se deberían trasladar las implementaciones de la clase actual a la nueva.

Con la clase ByteArray ocurre algo similar, la diferencia radica en que el método utilizado para subclasificar ArrayedCollection es:

variableByteSubclass:instanceVariableNames:classVariableNames:poolDictionaries:category:

Al igual que el mensaje anterior, la subclase tiene variables de punteros indexables, pero estas variables tienen el tamaño de un byte.

Tal como sucede con Array, algunos de sus métodos se implementan utilizando primitivas y se consideró innecesario implementar esta colección para cumplir con el objetivo del trabajo.

Respecto a las otras dos clases concretas no implementadas: String y Symbol, estas quedaron fuera del alcance, en parte, por el mismo motivo anteriormente expuesto para las clases Array y

Page 5: Capitulo 3 - Jerarquía Collection

ByteArray. La VM conoce la implementación de las mismas y hace uso de su estructura interna por lo tanto no es posible modificarlas. Además, su protocolo escapa al propio de las colecciones, ya que agrega protocolo definido en <Magnitude>.

El ANSI también define el protocolo para la creación de instancias de cada colección. Por ejemplo, el protocolo <collection factory> define los mensajes necesarios para crear una colección de objetos. Estos protocolos son mensajes que las clases del modelo a implementar deben saber responder.

En la Figura 3.2 se pueden visualizar todos los protocolos de creación de instancias que define el ANSI y las relaciones entre ellos.

Figura 3.2: Protocolos de creación de instancias de la jerarquía de Collection definidos por el ANSI.

Page 6: Capitulo 3 - Jerarquía Collection

Jerarquía de Collection en SqueakEn Squeak, como en toda implementación de Smalltalk, se encuentra desarrollado un modelo de la jerarquía de Collection. En esta sección se describe este modelo y además se realiza un análisis de los principales problemas del mismo.

DescripciónEn Squeak, la jerarquía de Collection cuenta con la implementación de las once colecciones concretas descriptas por el ANSI, sin embargo ésta jerarquía implementa una gran cantidad de comportamiento que no está relacionado con lo que se define en el ANSI. En concreto, la clase abstracta Collection cuenta con 98 subclases, donde muchas de estas (por ejemplo, CompiledMethod y Bitmap) son de propósito específico.

A continuación se realizará una descripción de la implementación en Squeak del protocolo definido por el ANSI, las clases que componen a esta jerarquía se pueden ver en la Figura 3.3.

Figura 3.3: Jerarquía de Collection en Squeak restringida al ANSI.

Page 7: Capitulo 3 - Jerarquía Collection

En Squeak la jerarquía comienza subclasificando a Object con la clase abstracta Collection. En ella se implementa gran parte del protocolo común a todas las colecciones definido por el ANSI. Sin embargo, gran parte de este protocolo es re-implementado por las subclases, en algunos casos para realizar optimizaciones y en otros porque las implementaciones que tiene Collection no respetan el comportamiento especial que requiere la clase que hereda este comportamiento.

Existen otras dos colecciones abstractas en el modelo: ArrayedCollection y SequenceableCollection. La primera de ellas es subclase de la segunda, donde la segunda es subclase de Collection y representa, según la documentación en Squeak, una superclase abstracta para colecciones que tengan un orden bien definido entre sus elementos. De esta manera, cada elemento puede ser referenciado externamente por un entero como si fuese un índice.

Además de la clase ArrayedCollection, en la cual se pondrá atención luego, de SequenceableCollection subclasifican dos de las clases concretas definidas por el ANSI: Interval y OrderedCollection. Esto parece tener sentido, ya que en ambas colecciones los elementos respetan un orden y pueden ser accedidos externamente a través de índices. Sin embargo, algo que llama la atención es que de OrderedCollection subclasifica SortedCollection. En la siguiente sección se hará especial hincapié en analizar este tipo de decisiones.

De la clase abstracta ArrayedCollection subclasifican otras tres clases concretas especificadas en el ANSI: Array, ByteArray y String. De esta última subclasifica Symbol.

Tanto Set como Bag subclasifican Collection implementando el comportamiento descripto por el ANSI. Por más que no parezca intuitivo, de Set subclasifica Dictionary. En la siguiente sección se analizará esta relación en detalle.

Por último queda IdentityDictionary, su superclase es Dictionary, que es quien provee todo el comportamiento definido para el protocolo abstracto <abstractDictionary>.

Análisis de la jerarquía de Squeak

En esta sección se realiza un análisis de la jerarquía de Collection de Squeak, describiendo los problemas más significativos encontrados. El análisis se basa fundamentalmente en las clases que forman parte del protocolo definido por el ANSI.

Como William Cook [6] mostró, en la jerarquía de Collection se intenta maximizar el reuso de código dejando de lado la categorización conceptual entre las clases. Por ejemplo, la clase Dictionary es subclase de Set. La decisión de relacionar estas clases a través de la subclasificación, está basada en que comparten su implementación sin considerar la diferencia conceptual entre lo que reifica cada clase. Este problema es denotado con el nombre: mal uso de la subclasificación.

Page 8: Capitulo 3 - Jerarquía Collection

Otra forma de maximizar el reuso de código es implementando mensajes en un nivel superior al que corresponde dentro de la jerarquía, buscando así que la mayor cantidad posible de subclases puedan responder a estos mensajes. A este problema se lo llamó métodos definidos muy arriba.

En la jerarquía de Collection de Squeak, otra problemática producto de la subclasificación mal utilizada, es la gran explosión de clases con la que cuenta, que se la titula como explosión de clases.

En lo que resta de esta sección se analiza con mayor profundidad cada uno de estos problemas de diseño.

Mal uso de la subclasificación

Dentro de la jerarquía de Squeak, se puede encontrar el mal uso de la subclasificación en varios ejemplos. En la Figura 3.4 vemos cómo la clase Dictionary es subclase de Set, cuando en la realidad no tienen relación conceptual. En cambio, su relación esta dada por como en Squeak se implementa Dictionary. La implementación de Dictionary utiliza un conjunto de asociaciones (instancias de la clase Association), las cuales relacionan a las claves con un valor.

FIGURA 3.4: Subclasificación mal utilizada entre Dictionary y Set.

Uno de los problemas que se pueden producir al realizar este tipo de subclasificación, es el de agregar en las subclases protocolo de las superclases y que éste no sea consistente con el concepto que se esta creando.

Un ejemplo concreto de este problema se puede visualizar en el mensaje #remove:, éste es heredado de la clase Collection. Claramente el mismo no forma parte del protocolo de los diccionarios, dado que el colaborador esperado en este mensaje es un elemento de la colección. En los diccionarios no es posible acceder a los elementos a menos que sea mediante una clave, por esto existe dentro de su protocolo el mensaje #removeKey:. Para solucionar este problema en la jerarquía de Squeak se cancela el mensaje #remove: implementándolo enviando el mensaje #shouldNotImplement, el cual es utilizado para declarar que el mensaje no debe ser definido en la clase.

Page 9: Capitulo 3 - Jerarquía Collection

Por otro lado, sucede algo similar con el mensaje #add:, pero con una solución diferente. La clase Dictionary puede responder al mensaje #add:, que también es heredado de su superclase, o sea Set. Así como con el mensaje #remove:, esto no tiene mucho sentido, ya que un diccionario se debe acceder mediante una clave (mensaje #at:) y eventualmente para esa clave, modificar o definir su valor (mensaje #at:put:).

Pero en este caso, el mensaje no es cancelado como #remove:, sino que recibe como colaborador una instancia de la clase Association. Por lo tanto, que el mensaje #add: definido en la clase Dictionary no es intuitivo para el programador. Además al recibir como colaborador a una instancia de la clase Association, está exponiendo hacia el exterior de qué manera se guardan los elementos.

El mal uso de la subclasificación en la jerarquía de Squeak también se puede observar en la clase SortedCollection, la cual es subclase de OrderedCollection. Más allá de entrar en discusiones sobre la relación conceptual entre SortedCollection y OrderedCollection, en este caso, el problema es de otra índole. En esta ocasión se está subclasificando a una clase concreta, lo cual es un error conceptual grave.

Como se mencionó anteriormente, esto se debe a que en la jerarquía de Squeak, se priorizó el reuso de código ante la utilización de la subclasificación como una herramienta para organizar conceptos.

Métodos definidos muy arriba

La subclasificación es muy utilizada dentro de la jerarquía de Collection, pero el uso excesivo de la misma ha llevado a la creación de una jerarquía más compleja de lo necesario.

Existen gran cantidad de métodos definidos muy arriba en la jerarquía que luego son sobrescritos en las subclases.

Inicialmente esto no parecería ser un inconveniente, ya que la posibilidad de definir comportamiento común en superclases para luego ser reutilizado desde sus subclases, es uno de los grandes beneficios que provee la subclasificación simple. La problemática se da porque la gran mayoría de veces este comportamiento definido en las superclases, no es expandido o utilizado por las subclases, sino que es sobrescrito y por lo tanto cancelado por las subclases.

Como consecuencia de este problema, la tarea de comprender el comportamiento definido en una clase que hereda varios métodos sin utilizarlos, pasa a ser más compleja de lo necesario.

Esto es así porque se supone que la subclasificación brinda al programador una herramienta intuitiva para comprender un modelo. Para hacerlo, en general se comienza el proceso de aprendizaje desde la raíz de la jerarquía, y luego se recorren las subclases analizando diferencias de comportamiento entre las clases y sus superclases.

Page 10: Capitulo 3 - Jerarquía Collection

Dado que existen métodos implementados en un nivel superior al correspondiente, el aprendizaje de la jerarquía se hace más complejo, ya que el programador no puede analizar las diferencias entre clases y superclases sino que tiene que considerar ambas en el proceso.

De esta manera, se logra que la subclasificación pase de ser un mecanismo para ayudar al programador, a uno que haga más compleja la tarea de comprender el modelo.

Un ejemplo de esta problemática se puede ver en la Figura 3.5. En este caso, el mensaje definido en un nivel superior al correspondiente es #collect:, el cual esta definido en la clase Collection.

FIGURA 3.5: Redefinición del mensaje #collect: en las superclases SortedCollection.

Dentro de la implementación del mensaje #collect: en la clase Collection, se envía el mensaje #add:, al cual no todas las subclases de Collection saben responder (por ejemplo, la clase Interval). Este problema genera que muchas subclases tengan que re-implementar este mensaje, por ejemplo la clase abstracta SequenceableCollection lo hace, utilizando el mensaje #at:put: en vez del #add: en su implementación.

Sin embargo OrderedCollection, que subclasifica SequenceableCollection, vuelve a implementar el mensaje #collect: pero en este caso utilizando el mensaje #addLast:. Por último, la clase SortedCollection que subclasifica OrderedCollection vuelve a implementar el mensaje #collect:. En este caso, es necesario modificar la clase resultante luego de recolectar los resultados, puesto que no se puede asegurar que al aplicar la transformación definida en el bloque enviado como colaborador en el mensaje, los resultados sean comparables entre si para permanecer ordenados.

Explosión de Clases

Otro problema que ocurre en la jerarquía de Squeak (se consideran aquí, a todas las clases de la jerarquía, no solamente a las definidas en el ANSI) es la gran explosión de clases que existe. Como

Page 11: Capitulo 3 - Jerarquía Collection

ya se mencionó en este capítulo, la misma cuenta con 98 subclases. Entre otros motivos, este inconveniente es una consecuencia del problema ya tratado de subclasificaciones mal utilizada.

El contar con una jerarquía de varios niveles, agrega mucha complejidad al programador a la hora de modificar la jerarquía y también para comprenderla. Por ejemplo cuando se crea una nueva clase, se hace muy complejo determinar cual es su superclase.

Se pueden citar varios ejemplos de clases que no corresponden dentro de la jerarquía de Squeak, como por ejemplo, CompiledMethod que representa a un método compilado, claramente este concepto no está relacionado con el dominio de las colecciones mas allá de utilizar a las colecciones como una posible implementación.

Nueva Jerarquía de CollectionEn esta sección se realiza un primer acercamiento a la jerarquía de clases definitiva generada para modelar las colecciones definidas por el ANSI. Cabe aclarar, que por ahora no se mencionarán los Traits que utiliza cada una de estas clases.

La nueva jerarquía generada se verá en capítulos posteriores, donde se transmite cómo evolucionó el modelo hasta llegar a su estado final y se muestran los Traits implementados. Dejando de esta manera, una idea clara de cómo está implementada la jerarquía.

En la Figura 3.6 se puede observar la jerarquía de clases, la cual muestra a Collection como superclase de todas las demás. Si bien no se ve en el gráfico, esta subclasifica a la clase Object.

Page 12: Capitulo 3 - Jerarquía Collection

Figura 3.6. Jerarquía de clases del nuevo modelo.

Como se puede ver en el gráfico Collection es una clase abstracta al igual que las clases DictionaryBehavior y SetBehavior.

DictionaryBehavior es superclase de las clases Dictionary e IdentityDictionary, en esta clase se agrupa el comportamiento común a los diccionarios y se delega a sus subclases algunos mensajes con el fin de que implementen lo que las diferencia, la equivalencia entre sus claves.

La otra clase abstracta es SetBehavior, de esta subclasifican las clases Set e IdentitySet. Si bien esta última no es definida por el ANSI, fue desarrollada para implementar comportamiento en IdentityDictionary.

Las demás clases concretas: Bag, OrderedCollection, SortedCollection e Interval, todas subclasifican directamente de Collection. Esto marca una notable diferencia respecto a la jerarquía

Page 13: Capitulo 3 - Jerarquía Collection

implementada en Squeak por diferentes motivos. En primer lugar, en este modelo ya no existe la clase abstracta SequencedCollection de donde subclasificaban OrderedCollection e Interval.

En segundo lugar, SortedCollection ya no es subclase de OrderedCollection. Esto parece ser razonable, ya que según el ANSI, OrderedCollection debe implementar cierto protocolo que no es propio de SortedCollection, y que esta última hereda a través de la subclasificación.

Una vez presentada la especificación del dominio, la cual fue tomada de guía durante el desarrollo, y luego de haber presentado la nueva jerarquía de Collection, se comenzará a explicar el modelo generado. Para esto se comenzará relatando la evolución del mismo, marcando las principales modificaciones realizadas durante el desarrollo, para luego presentar el modelo final generado. En este caso, se incluyen los Traits reificados y cómo estos son utilizados desde las clases del modelo.

Page 14: Capitulo 3 - Jerarquía Collection

Referencias

[11] William R. Cook. Interfaces and specifications for the Smalltalk-80 collection classes. In Proceedings OOPSLA ’92, ACM SIGPLAN Notices, volume 27, pages 1–15, October 1992.


Recommended