2009-07-23 22 views
9

Dla każdej podstawce z klasy trzeba zaimplementować pewne logiki zdarzenia (OnChanging, onChanged):Powtarzające ustawiaczy logika w 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; 

Czy możesz zaproponować sposób zaimplementować to bez powielania wszystkie te wiersze dla każdego seter?

+1

+1 VOR ogólny problem, że znajdziesz bardzo często w programowaniu baz zdarzeń. –

+2

Powinieneś najpierw sprawdzić wartość <> OldValue, jest to zwykle idiom używany w VCL. Albo na początku metody, albo po zdarzeniu OnChanging (zależy od tego, czy OnChanging otrzymuje parametr var, czy też nie, tj. Czy może zmienić nową wartość, czy nie). – mghie

Odpowiedz

13

Spróbuj tego:

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

w rzeczywistości - to tak samo jak moje rozwiązanie z ładniejszą składnią. –

+1

Nie tylko * ładniejsza * składnia, Tobiasz. * Poprawna * składnia. –

+0

I mistyped - Po prostu użyłem typu zamiast nazwy zmiennej. Poprawiłem swój przykład, nie miałem pod ręką żadnego kompilatora. Jak widać, jest to poprawna składnia. Pomysł pozostaje ten sam. Przekazujesz adres (za pomocą wskaźnika lub używając var). Kompilator robi to samo. Na poziomie binarnym wynik jest taki sam - po prostu składnia jest ładniejsza, jak mówiłem wcześniej. Nie jest nawet łatwiejszy w użyciu. –

0

Możesz dodać dodatkową metodę. Coś jak:

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; 

Nie skompilowałem/przetestowałem kodu. Chodzi o to, aby mieć ogólną metodę ustawiającą, która działa ze wskaźnikiem do lokalizacji. Wyspecjalizowane wersje nazywają właśnie metodę gerneral z adresem zmiennej, która ma zostać ustawiona. Musisz jednak mieć jeden typ ogólnej metody ustawiającej dla każdego typu zmiennej (double, integer, ...). Można go zmodyfikować, aby działał na wskaźniku i długość zmiennej do pracy ze wszystkimi typami - twoja decyzja, czy warto.

+0

Zamiast wskaźnika, powinieneś użyć parametru var, jak w sugestii Cobusa Kruger'a. – dummzeuch

+0

to tylko cukier syntaktyczny, chociaż lepiej go przeczytać. –

+1

@Tobias: Nie, nie tylko cukier syntaktyczny. Przy parametrze var niemożliwe jest podanie wskaźnika NULL, więc metoda SetValue() nie musi tego sprawdzać (BTW, twój kod nie!). Interfejs API o mniejszym potencjale do niewłaściwego użycia jest po prostu lepszy. – mghie

7

Delphi obsługuje indeksowane właściwości. Wiele właściwości mogą współużytkować jeden getter lub setter, zróżnicowanych w zależności od indeksu porządkowej:

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; 

można połączyć to z Cobus's answer uzyskać to:

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

To może dać Ci pomysły na inne sposoby można odwołaj się do twoich pól według indeksu zamiast mieć dwa całkowicie oddzielne pola dla takich powiązanych wartości.

+0

+1 bardzo interesujące! Nie wiedziałem o tym. – jpfollenius

+0

+1 za odpowiedź, którą prawie podałem, ale myślałem, że to za długo. Wygląda na to, że mimo wszystko można go nazwać zwartą :-) –

0

jeśli parametry procedury/funkcji są takie same i kod między początkiem a końcem są takie same, to możesz po prostu użyć

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

to jest to ...