‒ Creando y manejando colecciones.
Las colecciones TCollection, tienen los métodos y propiedades necesarios para su manipulación como son añadir, insertar, borrar elementos de una lista y otros más. Pero a diferencia de TFPList y Tlist, estos elementos deben ser clases heredadas de TColecctionItem.
Las colecciones se usan para representar listas de objetos que sean muy comunes entre ellos, como por ejemplo una lista de aviones, una lista de carros pero no una lista de aviones y mascotas. Es decir al momento de crear una colección, se debe definir cual será la clase padre al cual van a pertenecer todos los objetos de la colección. Esta clase padre debe ser siempre una subclase de la clase TCollectionItem.
En la siguiente tabla se explica brevemente algunos métodos de las colecciones TCollection.
Método | Descripción |
Create(i) | Constructor modificado, que permite crear una colección. El parámetro i se usa para indicar la clase padre del cual serán los objetos de la colección. |
Add | Permite crear y añadir al final un objeto nuevo a la colección. Devuelve una instancia de la clase padre. |
Insert(i) | Permite crear e insertar un objeto nuevo en la posición indicada por i. Devuelve una instancia de la clase padre. |
Delete(i) | Borra o destruye un objeto descendiente de la clase padre, en la posición indicada por i. |
Exchange(i,j) | Permite intercambiar dos objetos de la colección indicados por i y j. |
Clear | Borra todos los objetos de la colección llamando a su destructor correspondiente. |
Items[i] |
Es un atributo que nos permite acceder a un objeto. Si lo usamos para asignarlo a otro objeto de fuera de la colección devolverá un objeto de la clase TCollectionItem. Por ejemplo: obj:=coleccion.items[3] Es importante que obj, sea un objeto descendiente de la clase padre de la colección. Pero si lo usamos para asignar un objeto a otro objeto de la colección este usará el método Assign para asignar los atributos del objeto. Por Ejemplo: colección.items[3]:=obj; Es importante que el objeto que se quiera asignar a un objeto de la colección sea descendiente de la clase padre de la colección y que el método Assign TCollectionItem deba ser sobrescrito, con los mecanismos para asignar sus atributos correspondientes. Las colecciones se enumeran empezando con 0. Es decir el primer objeto de la colección es Items[0]. |
Count | Es un atributo que nos indica la cantidad de objetos que tiene la colección. |
Antes de crear una colección se debe definir la clase padre que se usará en la colección y esta debe heredar los atributos de TCollectionItem, cuando añadimos objetos a la colección se debe después añadir los atributos del objeto creado, para ello se debe usar un solapamiento con la clase padre de la colección. Ejemplo
En el ejemplo anterior se crean dos colecciones una de números enteros y la otro de números reales, para eliminar las colecciones lo recomendado es ejecutar el método free de cada colección, y evitar el uso de destroy. Al borrar o destruir la colección no necesitamos eliminar cada objeto de la colección, estos se eliminan por el destructor de la colección. Es decir el destructor de una colección se encarga de destruir cada uno de los objetos de la colección. Si no queremos eliminar la colección y sólo sus objetos entonces se debe usar el método clear, este método solo elimina los objetos de la colección.
Cuando accedemos a los objetos de la colección siempre se debe usar el solapamiento con el tipo de dato de la clase padre de la colección, para poder acceder a sus atributos. Si deseamos hacer una colección de cadena de caracteres del tipo ansistring o unicodestring, debemos hacer una clase que contenga el tipo de dato ansistring o unicodestring, del mismo modo como se uso en el ejemplo anterior para los números enteros y reales del ejemplo anterior. El siguiente ejemplo es una colección de objetos de la clase padre TPersona, que se vio en el código fuente 3 del capitulo anterior. Ejemplo:
El siguiente ejemplo muestra el uso de los métodos insert, delete, y exchange, en las colecciones no existe un método move, first y last. Pero el método move se puede implementar usando insert, delete y exchange, tomando en cuenta las siguientes consideraciones:
- Si el origen es mayor que el destino, entonces se inserta un objeto en el destino, se intercambia el origen+1 con el destino, y se borra el origen+1
- Si el origen es menor que el destino, entonces se inserta un objeto en el destino+1, se intercambia el origen con el destino+1, y se borra el origen.
A continuación el ejemplo:
En este ejemplo para añadir los objetos a la colección se hace uso de una clase padre que contiene un constructor, que nos permite colocar un contenido a la cadena de caracteres que tiene cada objeto.
Cuando insertamos un objeto a la colección en la posición indicada, los elementos a partir de la posición se desplazan todos a la siguiente, y como se puede observar al eliminar un objeto de la colección no es necesario eliminar el objeto individualmente como sucede cuando usamos listas, de eso se encarga el método Delete, que usamos para eliminar el objeto de la colección.
Los métodos Extract, Remove e IndexOf no tienen sentido que existan en una colección ya que los elementos de una colección no son simples punteros, pero existen situaciones en las que necesitamos extraer un objeto de una colección para colocarlo en otra, en esos casos debemos sobrescribir el método Assign de la clase TCollectionItems, para poder asignar los atributos de un objeto de una colección en otro y después borrar la anterior. El método Assign quedaría más o menos así:
Procedure TClasePadre.Assign(source:TPersistent);
Begin
if Source is TCadenas
then cad := TCadenas(Source).cad
else inherited Assign(Source);
End;
TClasePadre se refiere a la clase que se usará para crear el objeto, y después cuando deseamos trasladar de una colección a otro podríamos hacer lo siguiente:
coleccion02.add;
coleccion02.items[coleccion02.Count-1]:=coleccion01.items[5];
coleccion01.delete(5);
El ejemplo completo lo pueden ver a continuación:
Las colecciones no tienen un método Addlist que permite añadir los elementos de una lista en otra lista. Las colecciones por el contrario tienen un método Assign, no confundir con el Assign de TColleccionItem. Este método permite crear objetos en una colección y asignar los objetos de otra colección al mismo tiempo, usando el método Assign propio de cada objeto de la otra colección.
Para poder hacerlo se debe modificar el método Assign de TCollectionItem como lo hicimos anteriormente y luego usar el método Assign de la colección, pero este método no permite unir dos colecciones en una, ya que si volvemos a usar el mismo método este borrara los anteriores objetos antes de asignar los nuevos. Para tal situación si queremos asignar más objetos debemos hacerlo con un bucle for que permita adicionar más objetos, usando el método Add. Ejemplo:
En el ejemplo se puede observar el uso del bucle for, en el cual se hace un recorrido por todos los objetos de la colección02, para ir añadiéndolos a la coleccion03.
Hay situaciones en las que necesitamos extraer un objeto de la colección y que este ya no este en ella, para ello debemos de crear un objeto de la clase padre que lo contenga, para borrarlo posteriormente de la colección. El método create de la clase padre es un constructor sobrescrito de TCollectionItem, que usa un parámetro de tipo TCollection, que se usa para indicarle en que colección se debe añadir el objeto. El constructor se puede usar también para añadir objetos a una colección, pero si queremos crear un objeto de la clase padre, sin añadirlo a una colección debemos colocar nil como parámetro del método create, para indicarle que este objeto no pertenece a ninguna colección. A continuación el ejemplo.
En el ejemplo anterior se puede observar que para añadir nuevos objetos a la colección, se hace uso del constructor en ves de usar el método Add.
Al igual que las listas también se pueden usar los bucles for in loop, para ello se necesita de una variable de control que sea un objeto de la clase que se usa en la colección. Es decir el siguiente bucle:
for i:=0 to 10 do Writeln('[',i:2,'] ',Tinteger(ColeccionN.items[i]).n);
en donde Tinteger es la clase de todos los objetos de ColeccionN, se puede escribir del siguiente modo usando for-in-loop:
for TCollectionItem(n) in ColeccionN do Writeln('[',n.index:2,']',n.n);
En donde n es un objeto de la clase Tinteger al que se le hace un solapamiento con TCollectionItem, ya que el bucle for-in-loop espera que la variable de control sea un TCollectionItem cuando este trabaja con Colecciones. Aquí también se puede observar el uso del atributo index, este atributo es una herencia de TCollectionItem, y contiene el indice que le corresponde en la colección al objeto. El siguiente código fuente es el mismo ejemplo01 pero este hace uso de for-in-loop.