2011-06-17 16 views
5

Me preguntaba por qué debería usar propiedad en una clase en lugar de variables "normales" (¿atributos de clase?). Lo que quiero decir es esto:¿Por qué usar la propiedad en una clase?

TSampleClass = class 
    public 
    SomeInfo: integer; 
end; 

TPropertyClass = class 
    private 
    fSomeInfo: integer; 
    public 
    property SomeInfo: integer read fSomeInfo write fSomeInfo; 
end; 

¿Cuál es la gran diferencia? Sé que puedo definir métodos getter y setter para obtener o guardar la propiedad respectivamente, pero eso es posible incluso sin que la variable sea una "propiedad".

Traté de buscar por qué usarlo, pero no apareció nada útil, así que estoy preguntando aquí.

Gracias

+0

Magicmaster - Debo perderme algo aquí; ¿Puedes explicar cómo definirías un getter y un setter para tu ejemplo TSampleClass.SomeInfo, y de hecho harías que se invoquen esos métodos cuando asignes un valor o leas el valor de la variable SomeInfo? – Stuart

+0

Consulte esta pregunta: http://stackoverflow.com/q/3963874/267938 –

Respuesta

7

Esto es sólo un ejemplo muy simple de un caso específico, pero aún así, es un caso muy común.

Si tiene un control visual, puede necesitar volver a pintar el control cuando cambie una variable/propiedad. Por ejemplo, supongamos que su control tiene una variable/propiedad BackgroundColor.

La forma más sencilla de añadir una variable/propiedad tal es dejarlo ser una variable pública:

TMyControl = class(TCustomControl) 
public 
    BackgroundColor: TColor; 
... 
end; 

Y en el procedimiento TMyControl.Paint, se pinta el fondo usando el valor de la BackgroundColor. Pero esto no lo hace. Porque si cambia la variable BackgroundColor de una instancia del control, el control no se vuelve a pintar.En su lugar, el nuevo color de fondo no se utilizará hasta la próxima vez que el control se redibuje por alguna otra razón.

Así que hay que hacerlo de esta manera:

TMyControl = class(TCustomControl) 
private 
    FBackgroundColor: TColor; 
public 
    function GetBackgroundColor: TColor; 
    procedure SetBackgroundColor(NewColor: TColor); 
... 
end; 

donde

function TMyControl.GetBackgroundColor: TColor; 
begin 
    result := FBackgroundColor; 
end; 

procedure TMyControl.SetBackgroundColor(NewColor: TColor); 
begin 
    if FBackgroundColor <> NewColor then 
    begin 
    FBackgroundColor := NewColor; 
    Invalidate; 
    end; 
end; 

y luego el programador mediante el control tiene que utilizar MyControl1.GetBackgroundColor para obtener el color, y para utilizar MyControl1.SetBackgroundColor para establecer eso. Eso es incómodo.

Usando propiedades, puede tener lo mejor de ambos mundos. De hecho, si lo hace

TMyControl = class(TCustomControl) 
private 
    FBackgroundColor: TColor; 
    procedure SetBackgroundColor(NewColor: TColor); 
published 
    property BackgroundColor: TColor read FBackgroundColor write SetBackgroundColor; 
end; 

... 

procedure TMyControl.SetBackgroundColor(NewColor: TColor); 
begin 
    if FBackgroundColor <> NewColor then 
    begin 
    FBackgroundColor := NewColor; 
    Invalidate; 
    end; 
end; 

continuación

  • desde el punto de vista del programador, puede tanto leer y establecer el color de fondo utilizando un único identificador, la propiedad MyControl1.BackgroundColor, y
  • el control se repinta cuando lo establece!
+0

Olvidé mencionar algo muy importante. Algunas otras respuestas lo han tocado, pero me gustaría explicarlo con más detalle: cada propiedad que ve en Object Inspector (OI) es ... ¡una propiedad! En mi ejemplo anterior, la propiedad 'BackgroundColor' aparecería en la OI, por lo que podría modificar la apariencia del control en el momento del diseño. Y cuando cambia el valor, se ejecuta el código correspondiente para volver a dibujar el control, incluso en el momento del diseño. Si no hubiera usado una propiedad, sino solo una función 'GetBackgroundColor' y un procedimiento' SetBackgroundColor', la OI no sabría ... –

+0

... que el control tiene una propiedad llamada 'BackgroundColor', y que debería usar la función 'GetBackgroundColor' para leerlo y usar el procedimiento' SetBackgroundColor' para configurarlo. Este es un punto muy importante, ¡estoy seguro de que lo aprecias! De hecho, probablemente use propiedades todos los días. Por ejemplo, cuando cambia el 'Caption' de un' TButton', está usando la propiedad 'Caption' de la instancia' TButton'. Esto probablemente se lee de una variable de campo y tiene una función setter, por lo que el control se vuelve a dibujar a medida que escribe (en realidad, la propiedad 'Caption' no es' string', sino '' TCaption' ... –

+0

... que está definido por 'tipo TCaption = tipo cadena'. Entonces es una cadena, pero un tipo distinto, y para este tipo la OI sabe que debe usar el setter cada vez que se cambia el valor en la OI, y no solo cuando presiona Volver. Pero eso fue una nota al margen.) –

4

Hay ventajas de la vida real:

  • Las propiedades pueden ser cambiados a leer/escribir/read'n'write fácilmente, sin necesidad de molestar con todos los captadores y definidores separadas sobre el código;
  • Las propiedades pueden publicarse/publicarse en clases para niños simplemente agregando una línea en la sección de inicialización;
  • Las propiedades son más amigables cuando se trata de establecer campos, compare "Label.Font.SetSize (14)" con "Label.Font.Size: = 14", puede alinear ": =" con pestañas/espacios y código será mucho más legible;

EDIT: Otra cosa que pensé, las propiedades te obligan a limitar los métodos Get/Set a solo 1 parámetro, lo que es bueno para OOP. Compare esto con algunas funciones más de la ingeniería:

GetItem(Index:integer; ForcedIndex:boolean=false):TItem //Forced index to get any value 
GetItem(Index:integer; out Res:PItem):boolean //Result signals if out pointer is valid 
2

Es sólo una buena práctica de programación para aislar las mismas "entrañas" de la clase del mundo exterior. Además, la información sobre las propiedades publicadas se almacena en RTTI generada para la clase y se puede acceder por su nombre, enumerado, etc. Esta característica se usa, por ejemplo, cuando se lee un formulario de su formulario de recurso serializado.

0

No se puede controlar el cambio en una variable sin una propiedad.

sus lecturas/escrituras de propiedad no tienen que ser una variable, pueden ser funciones. Y luego puede administrar el "cambio" de una propiedad.

por ejemplo

TmyChange = procedure(Sender: Tobject) of object; 


private 
Fchange : TmyChange; 

public 
property SomeInfo: integer read getFoo write setFoo; 
property onChange : TmyChange read Fchange write Fchange; 

function getFoo : integer 
begin 
    return localFoo; 
end; 

function setFoo (value : integer) 
begin 
    // validate incoming value 
    localFoo=value; 
    if assigned(Fchange) then Fchange(self); 
end; 
+1

Encontré un error: en Delphi, no hay una declaración 'return'. –

+1

Encontré otro error: una función necesita un valor de retorno. –

+0

Y no hay 'Self 'a menos que la función sea un método de un objeto ... –

3

sé que puedo definir métodos getter y setter para conseguir o para salvar la propiedad, respectivamente, pero que es posible incluso sin la variable de ser una "propiedad".

Bueno, no. Setters y getters son solo métodos normales que se llaman como tales solo una vez que se utilizan como miembros de lectura y escritura de una propiedad. No tener una propiedad significa no tener un getter o un setter, incluso si se nombran como tales. Además; los setters y getters generalmente se declaran privados o protegidos. Por lo tanto, poder llamarlos cuando usa un campo público en lugar de usar una propiedad pública requeriría mover esos métodos a la sección pública.

Además, una gran diferencia entre los campos y las propiedades es la posibilidad de ser publicado y, por lo tanto, se puede utilizar en el inspector de objetos. Los campos (de otros tipos, luego clase o interfaz) no se pueden declarar como publicados.

Las propiedades también pueden ser de gran importancia, o ser útiles, en la herencia. Técnicamente, no puede anular una propiedad, pero puede imitar la anulación de varias maneras. Algunos ejemplos en los que la propiedad Name se puede llamar desde TDescendant, cada uno con su propio propósito:

1) Abstracción:

TBase = class(TObject) 
protected 
    function GetName: String; virtual; abstract; 
    procedure SetName(const Value: String); virtual; abstract; 
public 
    property Name: String read GetName write SetName; 
end; 

TDescendant = class(TBase) 
private 
    FName: String; 
protected 
    function GetName: String; override; 
    procedure SetName(const Value: String); override; 
end; 

2a) Protección (como Krom mencionado,):

TBase = class(TObject) 
private 
    FName: String; 
    function GetName: String; 
    procedure SetName(const Value: String); 
protected 
    property Name: String read GetName write SetName; 
end; 

TDescendant = class(TBase) 
public 
    property Name; 
end; 

2b)

TBase = class(TObject) 
private 
    FName: String; 
protected 
    function GetName: String; 
    procedure SetName(const Value: String); 
end; 

TDescendant = class(TBase) 
public 
    property Name: String read GetName write SetName; 
end; 

Por combinination de la anterior, puede chang e el comportamiento de las propiedades para las clases descendientes.

2

Una de las principales razones para usar propiedades (independientemente de que sea más OO) es la validación de la entrada, por ejemplo, si necesita limitar la edad de una clase de empleado para que esté en un rango válido como 18 ..40

TEmp = class 
    private 
    FName: string; 
    FAge: Integer; 
    procedure SetAge(const Value: Integer); 
    procedure SetName(const Value: string); 
    published 
    property Name:string read FName write SetName; 
    property Age:Integer read FAge write SetAge; 
    end; 

..... 

procedure TEmp.SetAge(const Value: Integer); 
begin 
    if not (Value in [18..40]) then 
    raise Exception.Create('Age must be between 18 and 40') 
    else 
    FAge := Value; 
end; 
+0

En su ejemplo, la validación es parte de su setter, no necesita una propiedad para tener un setter, solo puede hacer que su setter sea público (válido solo si realmente necesita que se publique su setter) – siwmas

Cuestiones relacionadas