2009-07-23 15 views
9

Para cada colocador de una clase que tengo que aplicar un poco de lógica evento (OnChanging, OnChanged):set repetidas en Delphi

procedure TBlock.SetWeightIn(const Value: Double); 
var OldValue: Double; 
begin 
    OldValue := FWeightIn; 
    DoOnChanging(OldValue, Value); 
    FWeightIn := Value; 
    DoOnChanged(OldValue, Value); 
end; 

procedure TBlock.SetWeightOut(const Value: Double); 
var OldValue: Double; 
begin 
    OldValue := FWeightOut; 
    DoOnChanging(OldValue, Value); 
    FWeightOut := Value; 
    DoOnChanged(OldValue, Value); 
end; 

¿Puede usted por favor sugerir una manera de poner en práctica esta sin duplicar todas estas líneas para cada ¿setter?

+1

1 vor problema general que encontrará muy a menudo en la programación de bases de eventos. –

+2

Primero debe verificar Value <> OldValue, es la expresión habitual que se utiliza en todo el VCL. Ya sea al inicio del método o después del evento OnChanging (depende de si OnChanging obtiene un parámetro var o no, es decir, si podría cambiar el nuevo valor o no). – mghie

Respuesta

13

Prueba esto:

procedure TBlock.SetField(var Field: Double; const Value: Double); 
var 
    OldValue: Double; 
begin 
    OldValue := Field; 
    DoOnChanging(OldValue, Value); 
    Field := Value; 
    DoOnChanged(OldValue, Value); 
end; 

procedure TBlock.SetWeightIn(const Value: Double); 
begin 
    SetField(FWeightIn, Value); 
end; 

procedure TBlock.SetWeightOut(const Value: Double); 
begin 
    SetField(FWeightOut, Value); 
end; 
+0

en realidad, sin embargo, eso es lo mismo que mi solución con una sintaxis más agradable. –

+1

No solo la sintaxis * nicer *, Tobias. * Sintaxis válida *. –

+0

Escribí mal: acabo de utilizar el tipo en lugar del nombre de la variable. Corregí mi ejemplo. No tenía un compilador a mano. Como puede ver, es una sintaxis válida. La idea permanece igual. Pasas la dirección (a través del puntero o usando var). El compilador hace lo mismo. En un nivel binario, el resultado es el mismo: solo la sintaxis es más agradable, como dije antes. No es aún más fácil de usar. –

0

Puede agregar un método adicional. Algo como:

procedure TBlock.setValue(const Value : Double; Location : PDouble); 
var 
    OldValue : Double; 
begin 
    OldValue:=Location^; 
    DoOnChanging(OldValue,Value); 
    Location^:=Value; 
    DOnChanged(OldValue, Value); 
end; 

procedure TBlock.setWeightOut(const Value : Double); 
begin 
    setValue(value, @FWeightOut); 
end; 

No he compilado/probado el código. La idea es tener un método de configuración general que funcione con un puntero a la ubicación. Las versiones especializadas solo llaman al método general con la dirección de la variable que se va a establecer. Sin embargo, debe tener un tipo de método de configuración general por tipo de variable (doble, entero, ...). Puede modificarlo para que funcione en Puntero y longitud de una variable para que funcione con todos los tipos: su decisión, si vale la pena.

+0

En lugar de un puntero, debe usar un parámetro var como en la sugerencia de Cobus Kruger. – dummzeuch

+0

que es solo azúcar sintáctica, aunque es más agradable de leer. –

+1

@Tobias: No, no solo azúcar sintáctico. Con el parámetro var es imposible pasar un puntero NULL, por lo que el método SetValue() no tiene que verificar eso (por cierto, ¡tu código no lo hace!). Una API con menos potencial de uso indebido es simplemente mejor. – mghie

7

Delphi apoya propiedades indexadas. propiedades múltiples pueden compartir un único captador o colocador, diferenciados por un índice ordinal:

type 
    TWeightType = (wtIn, wtOut); 
    TBlock = class 
    private 
    procedure SetWeight(Index: TWeightType; const Value: Double); 
    function GetWeight(Index: TWeightType): Double; 
    public 
    property InWeight: Double index wtIn read GetWeight write SetWeight; 
    property OutWeight: Double index wtOut read GetWeight write SetWeight; 
    end; 

Esto se puede combinar con Cobus's answer para conseguir esto:

procedure TBlock.SetWeight(Index: TWeightType; const Value: Double); 
begin 
    case Index of 
    wtIn: SetField(FWeightIn, Value); 
    wtOut: SetField(FWeightOut, Value); 
    end; 
end; 

Esto podría darle ideas para otras maneras en que puede consulte sus campos por índice en lugar de tener dos campos completamente separados para dichos valores relacionados.

+0

+1 muy interesante! No estaba enterado de esto. – jpfollenius

+0

+1 por la respuesta que casi di pero pensé que sería demasiado larga. Parece que todavía se puede describir de forma compacta después de todo :-) –

0

si los parámetros de procedimiento/función son del mismo y el código entre inicio y el fin son los mismos a continuación, puedes utilizar

procedure SetWeightValue(const Value: Double); 
var OldValue: Double; 
begin 
    OldValue := FWeightIn; 
    DoOnChanging(OldValue, Value); 
    FWeightIn := Value; 
    DoOnChanged(OldValue, Value); 
end; 

Eso es todo ...

Cuestiones relacionadas