Página principal
Artículos y trucos
Catálogo de productos
Ejemplos y descargas
Mis libros
Cursos de formación
Investigación y desarrollo
Libros recomendados
Mis páginas favoritas
Acerca del autor
 
En colaboración con Amazon
 
Intuitive Sight
 

Solución al Koan #3

TODOS LOS ANIMALES SON IGUALES...

Cuando uno lo piensa, se da cuenta de que la solución es evidente y trivial, pero si no nos detenemos a meditar, podemos formarnos imágenes mentales equivocadas como la del planteamiento. La solución, claro está, es que TListBox no almacena sus datos en un TStringList, sino en una clase ad-hoc llamada TListBoxStrings, que por supuesto también desciende de TStrings. Algo parecido sucede con otros componentes que "atacan" a controles nativos y que tienen propiedades TStrings, como TMemo, TRichEdit, etc.

La clase TListBoxStrings, por ejemplo, no utiliza memoria de la aplicación para sus cadenas, sino que gestiona directamente las cadenas situadas dentro del cuadro de listas asociado. Muestro a continuación un fragmento de la declaración de esta clase:

TListBoxStrings = class(TStrings)
private
    ListBox: TCustomListBox;
    // ...
end;

Veamos, por ejemplo, como TListBoxStrings redefine e implementa el método Add, que añade una nueva cadena al final de la lista:

function TListBoxStrings.Add(const S: string): Integer;
begin
    Result := SendMessage(ListBox.Handle,
        LB_ADDSTRING, 0, LongInt(PChar(S)));
    if Result < 0 then
        raise EOutOfResources.Create(SInsertLineError);
end;

Como vemos, la lista se añade a una estructura interna del control mediante un mensaje de Windows, LB_ADDSTRING. Para buscar una cadena, por otra parte, se utiliza el siguiente método:

function TListBoxStrings.IndexOf(const S: string): Integer;
begin
    Result := SendMessage(ListBox.Handle,
        LB_FINDSTRINGEXACT, -1, LongInt(PChar(S)));
end;

Y así sucesivamente. Los Items de un cuadro de lista, las Lines de un memo, la SQL de una consulta: sí, todos son TStrings, y comparten muchos métodos, pero la implementación de los mismos es diferente en cada caso. Lo maravilloso es cómo todos estos animales de especies diferentes pueden comunicarse entre sí, gracias al polimorfismo ("da igual gato blanco o gato negro, con tal de que cace ratones"). Cuando realizamos una asignación como la siguiente:

Memo1.Lines := ListBox1.Items;

estamos ejecutando en realidad el método Assign que está definido en la clase base TStrings, y en cuyo corazón encontraremos la siguiente instrucción (unidad Classes):

for I := 0 to Strings.Count - 1 do
    AddObject(Strings[I], Strings.Objects[I]);

Ese AddObject se ejecuta sobre las líneas del memo: será responsabilidad del TMemoStrings saber cómo almacenar una cadena. Ese otro valor Strings[I] se refiere al ListBox1: es responsabilidad del TListBoxStrings el suministrarnos la i-ésima cadena que contiene, y no nos importa a nosotros cómo las haya almacenado. Ventajas de la Programación Orientada a Objetos...