Frage

In einer Delphi-Anwendung, die wir auf arbeiten wir haben eine große Struktur von verwandten Objekten. Einige der Eigenschaften dieser Objekte haben Werte, die zur Laufzeit berechnet werden, und ich bin auf der Suche nach einer Möglichkeit, die Ergebnisse für die intensiveren Berechnungen zwischenzuzuspeichern. Ein Ansatz, den ich verwenden spart den Wert in einem privaten Mitglied zum ersten Mal berechnet wird. Hier ist ein kurzes Beispiel:

unit Unit1;

interface

type
  TMyObject = class
  private
    FObject1, FObject2: TMyOtherObject;
    FMyCalculatedValue: Integer;
      function GetMyCalculatedValue: Integer;
  public
    property MyCalculatedValue: Integer read GetMyCalculatedValue;
  end;

implementation

  function TMyObject.GetMyCalculatedValue: Integer;
  begin
    if FMyCalculatedValue = 0 then
    begin
      FMyCalculatedValue :=
        FObject1.OtherCalculatedValue + // This is also calculated
        FObject2.OtherValue;
    end;

    Result := FMyCalculatedValue;
  end;

end.

Es ist nicht ungewöhnlich, dass die Objekte für die Berechnung Änderung verwendet und der zwischengespeicherte Wert sollte zurückgesetzt und neu berechnet werden. Bisher haben wir uns dieses Problem durch die Beobachter-Muster mit: Objekte ein OnChange-Ereignis implementieren, so dass andere abonnieren, benachrichtigt, wenn sie im Cache gespeicherten Werte ändern und zurücksetzen. Dieser Ansatz funktioniert, hat aber einige Nachteile:

  • Es braucht viel Speicher-Abonnements zu verwalten.
  • Es ist nicht gut skalieren, wenn ein Cache gespeicherten Wert auf vielen Objekte (eine Liste zum Beispiel) abhängig ist.
  • Die Abhängigkeit ist nicht sehr spezifisch (auch wenn ein Wert Cache nur auf einer Eigenschaft hängt es wird auch zurückgesetzt werden, wenn andere Eigenschaften ändern).
  • Abonnements Auswirkungen auf die Gesamtleistung Verwaltung und schwer zu pflegen (Objekte werden gelöscht, verschoben, ...).
  • Es ist nicht klar, wie man mit Berechnungen in Abhängigkeit von anderen berechneten Werten befassen.

Und schließlich die Frage: kann vorschlagen, dass Sie andere Ansätze für gecached berechneten Werte Umsetzung

?
War es hilfreich?

Lösung

In meiner Arbeit, die ich verwende Bold für Delphi , das verwalten unbegrenzt komplexe Strukturen der im Cache gespeicherten Werte in Abhängigkeit von ihnen. Üblicherweise wird für jede Variable enthält nur einen kleinen Teil des Problems. In diesem Rahmen, der abgeleiteten Attribute genannt. Abgeleitet, weil der Wert nicht in der Datenbank gespeichert, es kommt nur darauf an auf anderen abgeleiteten Attributen oder persistente Attribute in der Datenbank.

Der Code hinter einem solchen Attribut wird als ein Verfahren in Delphi geschrieben oder in OCL (Object Constraint Language) im Modell. Wenn Sie es als Delphi-Code schreiben müssen Sie die abhängigen Variablen abonnieren. Also, wenn Attribut C hängt von A und B dann, wenn A oder B der Code für recalc C ändert sich automatisch aufgerufen wird, wenn C gelesen wird. So wird erstmals C lesen A und B auch (vielleicht aus der Datenbank) zu lesen. Solange A und B nicht geändert werden, können Sie C und bekommen eine sehr gute Performance lesen. Für komplexe Berechnungen kann diese sparen ziemlich viel CPU-Zeit.

Der Nachteil und eine schlechte Nachricht ist, dass Bold ist nicht mehr offiziell unterstützt und man kann es auch nicht kaufen. Ich nehme an, Sie können, wenn man genug Leute fragen, aber ich weiß nicht, wo Sie es herunterladen. Rund um 2005-2006 war es kostenlos von Borland herunterladbare aber nicht mehr. Es ist nicht bereit für die D2009 als jemand Portierung auf Unicode hat.

Eine weitere Option ist ECO mit dot.net von Capable Objekte . ECO ist ein Plugin in Visual Studio. Es ist eine unterstützte framwork, die die gleiche Idee und Autor als Bold für Delphi haben. Viele Dinge sind auch verbessert, zum Beispiel Datenbindung für die GUI-Komponenten verwendet. Sowohl Bold und ECO verwenden, um ein Modell als zentraler Punkt mit Klassen, Attributen und Links. Diese können in einer Datenbank oder einer XML-Datei beibehalten werden. Mit der kostenlosen Version von ECO kann das Modell max 12 Klassen haben, aber wie ich mich erinnere es keine anderen Grenzen liegt.

Bold und ECO enthält viel mehr als abgeleitete Attribute, die Sie produktiver macht und ermöglicht es Ihnen, das Problem zu denken, anstatt technischen Details der Datenbank oder in Ihrem Fall, wie Cache-Werte. Sie sind willkommen, mit mehr Fragen über diese Frameworks!

Edit: Es ist eigentlich ein Download Link für Embarcadero Registrierte Benutzer für Bold für Delphi für D7, ziemlich alt ... ich weiß, dass es Updates für D2005 war, ad D2006.

Andere Tipps

Wenn Sie das Observer-Muster vermeiden mögen, könnten Sie versuchen, einen Hashing-Ansatz zu verwenden.

Die Idee wäre, dass Sie ‚Hash‘ die Argumente, und prüfen, ob dieses Spiel der ‚Hash‘, für die der Zustand gespeichert wird. Wenn dies nicht der Fall, dann neu berechnen Sie (und damit zum Speichern der neuen Hash als Schlüssel).

Ich weiß, dass ich es klingen wie ich, wenn sie nur gedacht, aber in der Tat ist es von bekannter Software verwendet wird.

Zum Beispiel SCons (Makefile Alternative) ist es zu prüfen, ob das Ziel Bedürfnisse Wieder- sein vorzugsweise mit einem Zeitstempel Ansatz.

Wir haben SCons seit über einem Jahr verwendet jetzt, und wir entdeckt nie irgendein Problem Ziel, das nicht wieder aufgebaut wurde, so dass ihre Hash funktioniert gut!

Sie könnten speichern lokale Kopien der externen Objektwerte, die erforderlich sind. Die Zugriffsroutine vergleicht dann die lokale Kopie mit dem externen Wert, und nur, dass die Neuberechnung auf einem Wechsel.

Zugriff auf die externen Objekte Eigenschaften ebenfalls eine mögliche Neubewertung dieser Eigenschaften zwingen würde, so dass das System sich automatisch up-to-date halten sollte, sondern nur neu berechnet, wenn es muss. Ich weiß nicht, ob Sie Maßnahmen ergreifen müssen, um zirkuläre Abhängigkeiten zu vermeiden.

Dies erhöht die Menge an Speicherplatz Sie für jedes Objekt benötigen, aber entfernt die Beobachter-Muster. Es aufschiebt auch alle Berechnungen, bis sie gebraucht werden, anstatt die Berechnung jedes Mal, wenn ein Quellparameter ändert ausführt. Ich hoffe, das für Ihr System relevant ist.

unit Unit1;

interface

type
  TMyObject = class
  private
    FObject1, FObject2: TMyOtherObject;
    FObject1Val, FObject2Val: Integer;
    FMyCalculatedValue: Integer;
      function GetMyCalculatedValue: Integer;
  public
    property MyCalculatedValue: Integer read GetMyCalculatedValue;
  end;

implementation

  function TMyObject.GetMyCalculatedValue: Integer;
  begin
    if (FObject1.OtherCalculatedValue <> FObjectVal1)
    or (FObject2.OtherValue <> FObjectVal2) then
    begin
      FMyCalculatedValue :=
        FObject1.OtherCalculatedValue + // This is also calculated
        FObject2.OtherValue;
      FObjectVal1 := FObject1.OtherCalculatedValue;
      FObjectVal2 := Object2.OtherValue;
    end;

    Result := FMyCalculatedValue;
  end;

end.
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top