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 #1

CUANDO UNO SON DOS Y DOS SON UNO

En este caso, la solución es muy sencilla: hay que darse cuenta de que Memo.Font (y también FontDialog1.Font) no es una variable de clase, sino una propiedad de tipo clase ... y que las propiedades, aunque intentan engañarnos haciéndose pasar por variables, realmente no lo son. La propiedad Font se implementa generalmente del siguiente modo:

type
    TLoQueSea = class(TOtraCosa)
        // ...
    private
        FFont: TFont;
        procedure SetFont(Value: TFont);
    published
        property Font: TFont read FFont write SetFont;
  end;

La implementación del método de escritura SetFont es la siguiente:

procedure TLoQueSea.SetFont(Value: TFont);
begin
    FFont.Assign(Value);
end;

El método Assign es introducido por la clase TPersistent (ancestro de TComponent) y debe ser redefinido por aquellas clases que deseen implementar la asignación de objetos "propiedad por propiedad". En la jerga informática, a este tipo de asignación se le llama asignación por valor, en contraste con la asignación por referencia, que es la implementada por el operador de asignación de Delphi para las variables de tipo clase.

De modo que en el primer ejemplo realmente estabamos asignando el puntero del objeto original a la variable F, precisamente por tratarse de una variable. En el segundo ejemplo, la asignación se realizaba a una propiedad de tipo Font, y Delphi implementa las asignaciones a este tipo de propiedades como asignaciones por valor.

¿Hasta que punto podemos fiarnos de que Delphi implemente para todas sus propiedades de tipo clase asignaciones por valor? Se trata de una recomendación metodológica, que Delphi (hasta donde sé) cumple escrupulosamente. Cuando usted implemente una propiedad de tipo clase debe tener cuidado y ajustarse a este comportamiento. Por ejemplo, es fácil perder de vista el hecho de que la variable interna FFont debe ser construida a la vez que la clase que la contiene (y destruida en Destroy):

constructor TLoQueSea.Create(AOwner: TComponent);
begin
    inherited Create(AOwner);
    FFont := TFont.Create;
    // ...
end;

También es muy fácil olvidar el requisito de que la clase para la cual se define la propiedad debe contar con una implementación correcta del método Assign.