Ir al contenido



Foto

Concepto: Propiedades


  • Por favor identifícate para responder
10 respuestas en este tema

#1 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.280 mensajes
  • LocationArgentina

Escrito 03 enero 2009 - 06:03

En una anterior oportunidad se habló de ordenar una clase estableciendo su visibilidad.
Bueno, una consecuencia directa de este uso de la visibilidad es que se nos permite el uso de propiedades para dar mayor seguridad a los datos que suministramos a nuestros objetos.

El acceso a atributos o campos

Hasta ahora hemos venido declarando campos o atributos de forma pública, luego los ordenamos. Ahora una pregunta ¿De que sirve tener un atributo privado si no puedo acceder al mismo?
Uno diría, muy fácil: cambio su visibilidad a público y listo.

Esa es una opción. ¿Pero es la más adecuada? La respuesta es un depende.
Un peligro de hacer los campos y atributos de forma pública es que uno puede accidentalmente asignar un valor erróneo o no permitido sin ningún control. Por poner un ejemplo:



delphi
  1. type
  2.   TAuto = class(TVehiculo)
  3.   public
  4.     FVelocidad: double; // expresada en km/h
  5.   end;



Supongamos que uno desea destinar el uso de FVelocidad para guardar el valor de la velocidad del auto. Como es de esperar, el valor de ésta no es ni negativo ni mayor a la velocidad del sonido (el día que exista un auto a la altura del bosillo de la clase media que brinde dicha velocidad me retracto ;) :p) por lo que la pregunta es ¿cómo uno puede controlar que el valor ingresado es permitido?

Una solución que uno puede elaborar es un método que realice algo como esto:



delphi
  1. type
  2.   TAuto = class(TVehiculo)
  3.   public
  4.     FVelocidad: double; // expresada en km/h
  5.     function EsVelocidadValida: boolean;
  6.   end;



La implementación podría ser de la forma:



delphi
  1. function TAuto.EsVelocidadValida: boolean;
  2. begin
  3.   result := (FVelocidad > 0.0) AND (FVelocidad < VEL_SONIDO)
  4.   if NOT result
  5.     then FVelocidad := 0.0;
  6. end;



Siendo VEL_SONIDO alguna constante numérica que represente a la velocidad del sonido (por si a alguien le interesa es de 1224 km/h o 340 m/s)

Como bien he dicho... es una opción. Pero para trabajar apropiadamente tenemos que recurrir a algo como:



delphi
  1. var
  2.   Auto: TAuto;
  3.   valida: boolean;
  4. begin
  5.   Auto := TAuto.Create;
  6.   Auto.FVelocidad := 1224.555;
  7.   valida := Auto.EsVelocidadValida;
  8.   if valida
  9.      then ....



Ahora bien, otro puede hacerse la idea de que el atributo sea privado y disponer de métodos para escribir y leer del mismo. Algo como:



delphi
  1. type
  2.   TAuto = class(TVehiculo)
  3.   private
  4.     FVelocidad: double; // expresada en km/h
  5.   public
  6.     procedure EstablecerVelocidad(Valor: double);
  7.     function LeerVelocidad: double;
  8.   end;



Ahora en este caso, las implementaciones podrían ser como las siguientes:


delphi
  1. procedure TAuto.EstablecerVelocidad(Valor: double);
  2. begin
  3.   if (Valor > 0.0) AND (Valor < VEL_SONIDO)
  4.      then FVelocidad := Valor
  5.      else FVelocidad := 0.0;
  6. end;
  7.  
  8. function TAuto.LeerVelocidad: double;
  9. begin
  10.    result := FVelocidad;
  11. end;



Esta concepción es más cercana al tema que vamos a hablar en este hilo, pero todavía tenemos una pequeña molestia. Ahora tanto para escribir y leer debemos hacer cosas como:



delphi
  1. begin
  2.    Auto := TAuto.Create;
  3.    Auto.EstablecerVelocidad(1224.5555)
  4.    ...
  5.    variable := Auto.LeerVelocidad;



¿Un poco molesto no? Molesta la "vista" y complica al diseño y comprensión del problema. Imagínese que por cada atributo estaría haciendo 2 métodos...

¿Se podría tener algo como esto?:


delphi
  1. Auto.Velocidad := 1224.555;
  2. variable := Auto.Velocidad;



Si, todo es posible gracias a las propiedades.

Las propiedades existen para brindar un acceso seguro a nuestros atributos. De este modo uno puede disponer de atributos privados y dejar que las propiedades se encarguen de la parte "sucia". Contar con propiedades nos permiten hacer más fácil las cosas, nos ahorramos lineas de código y nos esclarece el panorama.

Seguiremos el tema en el próximo post.

Saludos,
  • 0

#2 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.409 mensajes
  • LocationRepública Dominicana

Escrito 03 enero 2009 - 06:19

Esto es la hostia amigo, excelente tutorial (y), muchas gracias.

Saludos.
  • 0

#3 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.280 mensajes
  • LocationArgentina

Escrito 03 enero 2009 - 06:36

Gracias amigo :) :D
Ahorita se pone interesante el tema.

Saludos,


  • 0

#4 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.280 mensajes
  • LocationArgentina

Escrito 03 enero 2009 - 08:05

Propiedades

Bueno ahora que se ha introducido el tema, sería oportuno hablar más de lo que es una propiedad.
De forma simple se puede decir que es una especie de campo o atributo que permite tener acceso de escritura y lectura a un campo en particular.

Las propiedades se declaran del siguiente modo:



delphi
  1. property NombrePropiedad: Tipo read MetodoLectura write MetodoEscritura;



Las propiedades pueden tener cualquier visibilidad, aunque lo esperado es que sean protegidas públicas y/o publicadas.
NombrePropiedad es el nombre que se le asigna, si seguimos el ejemplo anterior sería "Velocidad". Tipo indica al tipo de dato que se maneja y debe coincidir con el del atributo. En este caso es double.
read xxx y write yyy sirven para indicar el tipo de acceso al atributo. Read para lectura y write para escritura.
MetodoLectura y MetodoEscritura deben ser dos métodos que servirán para leer o escribir en el atributo.

Necesariamente MetodoEscritura debe ser un procedimiento con un sólo parámetro y del mismo tipo que del atributo. MetodoLectura debe ser una función sin parámetro que regrese el mismo tipo.

Los métodos pueden ser de cualquier visibilidad, aunque por lo general son privados y protegidos.

Siguiendo el ejemplo, obtendríamos algo como esto:



delphi
  1. type
  2.   TAuto = class(TVehiculo)
  3.   private
  4.      FVelocidad: double; // atributo o campo
  5.      function LeerVelocidad: double; // método de lectura
  6.      procedure EstablecerVelocidad(Valor: double); // método de escritura
  7.   public
  8.      property Velocidad: double read LeerVelocidad write EstablecerVelocidad; // Nuestra propiedad
  9.   end;



La implementación de estos métodos puede ser como la anterior. Por ahora es de menos. Lo importante es entender el concepto. Se debe respetar el orden de read y write, es decir primero el método de lectura y luego el de escritura.

Ahora si podemos hacer tranquilamente algo como:


delphi
  1. Auto.Velocidad := ... // establecemos un valor a la propiedad velocidad
  2. variable := Auto.Velocidad // leemos el valor de la propiedad velocidad



Ahora uno puede preguntarse ¿Es necesario contar con los métodos? La respuesta es un NO. De hecho uno puede hacer esto:



delphi
  1. property Velocidad: double read FVelocidad write FVelocidad;



En este caso está indicando que se leerá y se sobreescribirá el valor desde y hacia FVelocidad.
Puedo uno mezclar ambas cosas:



delphi
  1. property Velocidad: double read FVelocidad write EstablecerVelocidad;



En este último ejemplo, leemos desde FVelocidad pero en cambio indicamos que para escribir en FVelocidad nos valemos del método.

¿Cuando conviene usar método y cuando emplear el acceso directo al atributo?
La respuesta es que depende de las circunstancias. Vuelvo a decir lo que dije casi al final del primer mensaje: acceso seguro.
En principio las propiedades están concebidas para que uno pueda ofrecerle los medios necesarios para controlar que los valores suministrados y leídos sean los correctos. Si es necesario o adecuado implementar un mecanismo de control, declare un método; en otro caso puede hacer un acceso directo al campo.

Método de lectura vs atributo

Uno puede pensar que el método de lectura es redundante, puesto que si el acceso de escritura está controlado, se puede inferir que el valor leído es correcto. En ocasiones es cierta esa afirmación y por tanto nos evitamos tener otro método leyendo directamente desde el campo:



delphi
  1. Property Velocidad: double read FVelocidad write EstablecerVelocidad;



Ahora piense que desea leer y escribir la velocidad de diferentes formas: km/h y m/s. Uno puede sentirse en la necesidad de tener dos atributos con sus correspondientes propiedades y métodos:



delphi
  1. type
  2.   TAuto = class(TVehiculo)
  3.   private
  4.     Fkmh: double; // km/h
  5.     Fms: double; // m/s
  6.     // metodos
  7.     procedure EstablecerKmh(Valor: double);
  8.     procedure Establecerms(Valor: double);
  9.   public
  10.     property kms: double read Fkmh write Establecerkmh;
  11.     property ms: double read Fms write Establecerms;
  12.   end;



Las implementaciones las podemos obviar por el momento, la idea es mostrar una posible alternativa. Yo le pregunto a usted ¿Y porqué no nos evitamos esos dos atributos y empleamos uno?
¡Claro que podemos! Nos evitamos guardar el dato en forma "repetida". Propongo dos métodos de lectura que lean el mismo atributo. Cada uno se encarga de leer y "transformar" el atributo según sea conveniente a la unidad de medición adecuada. De forma un tanto similar, los métodos de escritura se encargan de hacer la conversión a una unidad básica (a modo de simplificar el ejemplo, supongamos que sea m/s). De este modo, independiente si lo que usamos es km/h o m/s el valor del atributo reflejará el contexto:



delphi
  1. type
  2.   TAuto = class(TVehiculo)
  3.   private
  4.     FVelocidad: double;
  5.     // metodos
  6.     function Leerkmh: double;
  7.     function Leerms: double;
  8.     procedure EstablecerKmh(Valor: double);
  9.     procedure Establecerms(Valor: double);
  10.   public
  11.     property kms: double read Leerkmh write Establecerkmh;
  12.     property ms: double read Leerms write Establecerms;
  13.   end;



Ahora si es necesario ver como se lleva la implementación:



delphi
  1. function TAuto.Leerkmh: double;
  2. begin
  3.   result := FVelocidad * 3.6; // 1m/s = 3,6 km/h
  4. end;
  5.  
  6. function TAuto.Leerms: double;
  7. begin
  8.   result := FVelocidad;
  9. end;
  10.  
  11. procedure TAuto.Establecerkmh(Valor: double);
  12. begin
  13.   FVelocidad := Valor / 3.6;
  14. end;
  15.  
  16. procedudre TAuto.Establecerms(Valor: double);
  17. begin
  18.   FVelocidad := Valor;
  19. end;



Es un ejemplo sencillo, lo correcto sería añadir ese EsVelocidadValida, pero a fin de hacer un ejemplo simple, lo podemos obviar. Como puede apreciarse, no interesa si lo que se suministra es km/h, o m/s, en el atributo FVelocidad quedará el valor expresado en una unidad de medición "patrón" previamente elegida. Luego, al leerlo se hace la conversión. Note que nunca se altera el valor de FVelocidad cuando se lee el valor.

Ahora de forma muy tranquila podemos hacer esto:



delphi
  1. Auto := Auto.Create;
  2. Auto.kmh := 80;
  3. variable := Auto.ms; // 80/3,6 = 22,22 m/s



Este es un ejemplo donde el uso de un método de lectura es altamente recomendado: "Expresar" un mismo atributo en diversos "formatos" sin tocar el valor real del atributo leído.

NOTA: repasando el temario acabo de recordar que los métodos de escrituras no pueden ser sobrecargados.

Seguiremos hablando del tema en otro post.

Saludos,
  • 0

#5 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.280 mensajes
  • LocationArgentina

Escrito 03 enero 2009 - 10:04

Propiedades de solo lectura y escritura

Anteriormente hemos visto que para definir una propiedad hacemos uso de dos métodos: uno para la lectura y otro para la escritura. En ocasiones es necesario contar con propiedades de sólo lectura y de sólo escritura. Esto se consigue añadiendo después del tipo la clásula "read Metodo" o "write Metodo" según sea el caso.



delphi
  1. property PropiedadLectura: integer read MetodoLectura;
  2. property PropiedadEscritura: integer write MetodoEscritura;



De forma análogo, podemos tener acceso directo al campo o atributo reemplazando el método por el nombre del atributo.

Recuerde que si debe ser de lectura/escritura debe respetarse el orden: read primero y write después.

¿Cuando es necesario el sólo lectura y/o escritura?
No hay una respuesta directa y sencilla. Al menos yo no me atrevería a afirmar cuando si, y cuando no. Es una cuestión de necesidad.

Afortunadamente es muy poco frecuente el caso de propiedades de sólo escritura. No es el así el caso de una propiedad de sólo lectura.
Una propiedad de sólo lectura nos permite leer atributos que no se desean darle la opción de alterar al programador cliente. Uno puede preguntarse ¿Y cómo es que se altera el valor de la propiedad? En realidad no se altera el valor mediante la propiedad, sino que de forma inmediata al atributo. Es muy recomendable aplicar este enfoque cuando se tiene una serie de procesos que alteran uno o más atributos de un objeto, y de los cuales no tiene intervención (ni debería) alguna el programador. Por lo general el valor inicial del atributo se establece al momento de crear el objeto (tal vez, posiblemente el valor sea pasado como un parámetro del constructor) y luego se hace lectura de dicho atributo cuando tras una serie de procesos se lo modifica. Estas propiedades tienden a reflejar el estado interno de un objeto. Por ejemplo a la propiedad State de un TDataSet no se le permite modificar el valor sino es a través de los métodos Insert, Post, Append, etc.

Continuaremos el tema. No se me aburran.
Saludos,
  • 0

#6 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.043 mensajes
  • LocationMéxico

Escrito 03 enero 2009 - 10:10

Perfecto, ya voy comenzando a entender este asunto, me hacen falta muchas horas de vuelo :)

Salud OS
  • 0

#7 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.280 mensajes
  • LocationArgentina

Escrito 03 enero 2009 - 10:18

Perfecto, ya voy comenzando a entender este asunto, me hacen falta muchas horas de vuelo :)

Salud OS

Me alegro de que sirva mi tutorial amigo :).
¿Horas de vuelo? Ummm tal vez el próximo post te permita llegar más rápido a tu destino ;)

Saludos,
  • 0

#8 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.043 mensajes
  • LocationMéxico

Escrito 03 enero 2009 - 10:25

Esa es la idea amigo Delphius.

Salud OS
  • 0

#9 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.280 mensajes
  • LocationArgentina

Escrito 03 enero 2009 - 11:29

Propiedades vectoriales

Ya se ha visto que las propiedades son una buena manera de ahorrarnos muchos dolores de cabeza, son una buena herramienta para controlar el acceso a atributos privados y nos facilita la comprensión del código enormemente.
El post del compañero Egostar me ha dado una idea, y la voy a aprovechar para explicar este sub-temario e ir mucho más lejos.

LLegó el turno de ver las propiedades vectoriales.
Hasta el momento trabajamos con tipos simples, pero las propiedades pueden ir más lejos. Supongamos que usted tiene una lista de algo, no importa el tipo la cuestión es que tiene una lista y considera de utilidad brindar la posibilidad de acceder a cada elemento por un índice. ¿Lo podemos hacer con propiedades? SI. para ello están las propiedades vectoriales.

En forma breve las propiedades vectoriales nos permiten acceder a un elemento de alguna lista atributo, según el índice.

La forma de declararlo es como sigue:



delphi
  1. property NombrePropiedad[Indice: TipoIndice]: Tipo read MetodoLectura write MetodoEscritura;


Lo único nuevo es que se declara entre corchetes el nombre de un índice y el tipo del mismo.
Un ejemplo de declaración de esta propiedad la encontramos en la clases que desciende de TStrings: la propiedad Items:



delphi
  1. property Items[I: integer]: Pointer read GetItems write SetItems; default;


Básicamente se indica que el tipo de la propiedad es un puntero, y que para acceder a cada elemento debemos hacer uso de un entero.

Podemos emplear propiedades vectoriales de cualquier tipo. Incluso en el índice, a diferencia de los vectores simples en donde sólo se permiten tener valores ordinales. De modo que es válido tener algo como esto:


delphi
  1. property Listado[A: string]: integer read LeerListado write EscribirListado;



A diferencia de las propiedades escalares (las normales) ahora si es obligación hacer uso de los métodos de lectura y escritura. ¿Porqué? Porque sin ellos no se puede tener acceso real y al elemento de la lista en cuestión. Por ello el método de lectura debe ser una función monoparamétrica que reciba el índice en cuestión; y por tanto debe ser del mismo tipo que el índice declarado para la propiedad, y el método de escritura un procedimiento que reciba como primer parámetro el indice y como segundo el valor a asignar en dicha posición de la lista. Por ejemplo, inspirados en el deseo del compañero Egostar deseamos ir por avión a múltiples destinos:



delphi
  1. Type
  2.  TListaDestino = array[1..MAX_DESTINOS] of string;
  3.  TAvion =class(TVehiculo)
  4.  private
  5.     FListaDestino: TListaDestino; //nuestro atributo
  6.     // métodos
  7.     function LeerDestino(Indice: integer): string;
  8.     procedure EstablecerDestino(Indice: integer; Valor: string);
  9.  public
  10.    property Destino[Indice: integer]: string read LeerDestino write EstablecerDestino;
  11.  end;



Ahora podemos hacer cosas como:



delphi
  1. Avion := TAvion.Create;
  2. Avion.Destino[1] := 'Argentina';
  3. Avion.Destino[MAX_DESTINOS] := 'Japón';
  4. ...
  5. Destino := Avion.Destino[4];



¿Que deben hacer los métodos de lectura y escritura? Por empezar deberían encargarse de chequear que el índice pasado como parámetro esté dentro de los límites permitidos. Si la pregunta que se está haciendo es  ¿Hasta donde es el límite? La respuesta es hasta donde usted y la definición del tipo del índice lo permita. El manejo de como llevar la lista es a gusto y definición del programador. Lo que se le exige al programador es que respete el uso de las declaraciones de los métodos y que se pueda acceder al elemento en cuestión.
En caso de que el índice pasado a la propiedad esté fuera del rango el compilador arrojará una excepción.

Una posible implementación sencilla de los métodos puede ser:



delphi
  1. function TAvion.LeerDestino(Indice: Integer): string;
  2. begin
  3.  if IndiceValido(Indice)
  4.     then result := FListaDestino[Indice]
  5.     else result := '';
  6. end;
  7.  
  8. procedure TAvion.EstablecerDestino(Indice: integer; Valor: string);
  9. begin
  10.   if IndiceValido(Indice)
  11.      then FListaDestino[Indice] := Valor;
  12. end;



Siendo IndiceValido posiblemente algún método privado de la clase TAvion que no se consideró oportuno remarcar en la declaración de la clase en el ejemplo anterior.

Nuevamente el propósito de los métodos es brindar un acceso seguro a la información.

Propiedad por default
Anteriormente se mencionó como ejemplo la propiedad Items de la clase TStrings. Puede verse que al final se añadió la cláusula default.
Esta cláusula le permite a una propiedad vectorial actuar como una propiedad por defecto. Lo cual es una buena ventaja que esto significa evitarnos escribir el nombre de la propiedad y directamente acceder a los elementos con el índice. Un ejemplo es como sigue:



delphi
  1. elemento := Lista[0];



Si la propiedad Destino fuera declarada como default podríamos hacer cosas como:



delphi
  1. Destino := Avion[0];
  2. Avion[2] := 'Costa Rica';



La condición que se nos exige es que exista una única propiedad vectorial por defecto. Incluso, es valido cuando se propaga la descendencia. Es decir que si por alguna cuestión necesitamos diseñar una clase descendiente de TAvion y queremos establecer otra propiedad vectorial por default el compilador nos los advierte. En el caso de que sea TVehiculo (la clase base de TAvion) tuviera una propiedad vectorial por defecto, el compilador nos daría una advertencia.

Ahora nos resta ver un tipo especial de propiedad. No se me duerman.
  • 0

#10 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.280 mensajes
  • LocationArgentina

Escrito 04 enero 2009 - 01:36

Propiedades indexadas

Si pensaba que hasta allí llega el poder de las propiedades mejor que se consiga una silla (o una cama, lo que prefiera) porque con éste tema si que asombrará.

¿Que me diría usted si yo le digo que es posible hacer que varias propiedades de un mismo tipo puedan compartir los mismos métodos de acceso?
Si piensa que estoy chillado, lo invito a hacer esto:



delphi
  1. const
  2. MAX_PARTES: 4;
  3.  
  4. Type
  5.   TAuto = class(TVehiculo)
  6.      private
  7.        FPartesAuto: array[1..MAX_PARTES] of string; // nuestro listado de propiedades "comunes"
  8.        // métodos
  9.        function LeerPropiedad(IndiceProp: integer): integer;
  10.        procedure EstablecerPropiedad(IndiceProp: integer; valor: string);
  11.      public
  12.        // las propiedades comunes
  13.        property PartesUno: string index 1 read LeerPropiedad write EstablecerPropiedad;
  14.        property PartesDos: string index 2 read LeerPropiedad write EstablecerPropiedad;
  15.        property PartesTres: string index 3 read LeerPropiedad write EstablecerPropiedad;
  16.        property PartesCuatro: string index 4 read LeerPropiedad write EstablecerPropiedad;
  17.        
  18.        // una propiedad común para acceder a cualesquiera de las comunes
  19.        property Partes[IndiceParte: integer]: string read LeerPropiedad write EstablecerPropiedad;
  20.    end;
  21.  
  22. function TAuto.LeerPropiedad(IndiceProp: integer): string;
  23. begin
  24.   result := FPartesAuto[IndiceProp];
  25. end;
  26.  
  27. procedure TAuto.EstablecerPropiedad(IndiceProp: integer; Valor: string);
  28. begin
  29.    FPartesAuto[IndiceProp] := Valor;
  30. end;



¿Que hay de nuevo? Note que antes de la declaración del acceso a la propiedad se añadió una cláusula "index" y un número. Con esta cláusula indica que la propiedad es una propiedad indexada y el número que le corresponde es el declarado. Básicamente está indicando que al emplear el índice 1, accederemos a la propiedad PropiedadUno.

Si se declara una propiedad como indexada, necesariamente se debe hacer uso de métodos para acceder al atributo o campo. Estos métodos necesitan de un parámetro extra del tipo integer para poder identificar a la propiedad. En el caso del método de lectura este parámetro debe ser el último, para los métodos de escritura debe ser el segundo al penúltimo parámetro (dependiendo de la cantidad de parámetros que se necesiten). El último parámetro debe ser el que se asociará al valor.

Ahora uno puede sentirse en libertad de acceder a las propiedades de estas formas:



delphi
  1. Auto := TAuto.Create;
  2. Auto.PartesUno := 'Llantas'; // accedemos a la propiedad 1 (PartesUno). Index = 1
  3. Auto.Partes[3] := 'Asientos'; // accedemos a la propiedad 3 (PartesTres). Index = 3
  4. ...
  5. parte := Auto.Partes[3];
  6. parte := Auto.PartesUno;



Propiedades: uso internamente

Algo que ha quedado un poco suelto es el tema de que hace cuando el compilador detecta el uso de una propiedad. Básicamente lo que es llamar o invocar al método adecuado según la necesidad. Por ejemplo, en el caso de:



delphi
  1. Auto.Velocidad := 80;



Lo que internamente sucede es algo como esto:



delphi
  1. Auto.EstablecerVelocidad(80);



Con las propiedades vectoriales el caso es similar:



delphi
  1. Destino := Avion[4]; // es equivalente a decir:
  2. Destino := Avion.LeerDestino(4);



Y con las indexadas no es la excepción:



delphi
  1. Auto.PartesDos := variableTuerca + 'Nro 10'; // equivale a:
  2. Auto.EstablecerPropiedad(2, variableTuerca + 'Nro 10');



Me quedaría en el tintero un pequeño temita (si, va a ser cortito... puede respirar tranquilo ;) :)) más, pero lo dejamos para otro post y en otra ocasión.

Saludos,
  • 0

#11 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.280 mensajes
  • LocationArgentina

Escrito 04 enero 2009 - 01:36

Stored y default

Para finalizar el tema, debo hablar de dos cláusulas que sólo tiene sentido y uso práctico cuando las propiedades son publicadas (published).

Normalmente todas las propiedades publicadas se graban en el archivo dfm, que luego el componente lee y extrae los valores. Con store y default podemos alterar un poco el comportamiento indicando cuando guardar en el dfm los valores.

El requisito fundamental para que esto funcione es que las propiedades sean escalares del tipo ordinal (enteros, enumerativos, etc) o a tipos de conjunto que tenga un máximo de 32 elementos. Por ejemplo en el caso de propiedades vectoriales no se puede.

Añadiendo la cláusula default seguida de un valor del mismo tipo de la propiedad estamos indicando el valor por defecto que asumirá dicha propiedad. Por ejemplo:



delphi
  1. type
  2.   TAutoPersistente = class(TPersistent) // recuerde que si usa published, deben heredar de ésta clase
  3.   ...
  4.   published
  5.      property CantidadPuertas: integer read FCantidadPuertas write EstablecerCantidadPuertas default 4.
  6.   end;



Tenga presente que "por defecto" no quiere decir que hace la inicialización a dicho valor. Es necesario inicializar el valor en el constructor que se haya definido.
En realidad lo que se consigue con default es que si el valor suministrado a la propiedad es igual al indicado en la cláusula se evita guardar el dato en el archivo dfm. Luego, al momento de leer dicho archivo el componente sabrá que le corresponde el valor 4.

Con stored le indicamos si queremos que guarde o no el valor en el fichero dfm dependiendo de una constante lógica o un método que regrese un valor booleano. Pueden haber ciertos casos en donde queremos disponer de una propiedad publicada pero que no se guarde el valor. Veamos unos ejemplos:



delphi
  1. TAutoPersistente = class(TPersistent)
  2. private
  3.   FCantidadPuertas: integer;
  4.   function PuedeGuardar: boolean;
  5. published
  6.   property CantidadPuertas: integer read FCantidadPuertas write EstablecerCantidadPuertas stored PuedeGuardar;
  7.  
  8. function TAutoPersistente.PuedeGuardar: boolean;
  9. begin
  10.    result :=  (FCantidadPuertas <> 4);
  11. end;



Como puede apreciarse, se hace uso de un método privado PuedeGuardar para indicar que si el valor es distinto de 4 que se guarde en el archivo dfm. En otro caso no. De este modo conseguimos el mismo efecto que en el ejemplo anterior.

En el siguiente ejemplo estamos indicando que SIEMPRE guarde el valor ya que la condición lógica es verdadera:



delphi
  1. property Nombre: string read FNombre write LeerNombre stored true;



Con esto damos por finalizado el temario de las propiedades.

Saludos,
  • 0