Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Strategie für Propertyvergleich verschiedener Objecte (https://www.delphipraxis.net/192497-strategie-fuer-propertyvergleich-verschiedener-objecte.html)

Hobbycoder 24. Apr 2017 10:55


Strategie für Propertyvergleich verschiedener Objecte
 
Der Titel ist nicht ganz eindeutig drum erkläre ich mal was ich machen möchten.
Gegeben ist eine dynamische Menge von Objekten, die jeweils mehrere Eigenschaften haben (können). Diese Eigenschaften lese ich per JSON aus einem entfernten System aus, dessen verhalten ich nicht beeinflussen kann.

Beispiel für ein Object:
Code:
TElement.Name
Telement.id  //eindeutig
TElement.Temperatur
TElement.Luftdruck
TElement.Luftfeuchte
Die Objecte wohnen zur Zeit alles in einer TObjectList.

Nun möchte ich dem User die Möglichkeit geben, bei Eintreten bestimmter Werte Aktionen auslösen zu lassen. Diese Werte soll er aus unterschiedlichen Objecte und unterschiedlichen Eigenschaften zusammensetzen können, und es muss sowohl <Und> als auch <Oder> Bedingungen geben, wobei deren Anzahl nicht vorgegeben sein soll.
Als Code-Beispiel würde das so aussehen:
Delphi-Quellcode:
if (Element[0].Temperatur>18) and ((Element[0].Luftdruck=1) or (Element[1].Temperatur<15)) then
Von diesen definierten Aktionen soll es dann x-beliebige gehen, die separat gespeichert werden sollen.

Ich zerbreche mir schob einige Zeit den Kopf, wie ich sowas in eine Klasse packen kann, so dass diese sich selber auswerten kann und dann ggf. ein True zurück liefert. Mein Problem sind a) dass es je mehrer Bedingungen geben soll, und b) diese auch noch unterschiedlich (und/oder) miteinander verknüpft sein sollen.
Bin für jeden Anreiz dankbar.

Gruß Hobbycoder

Der schöne Günther 24. Apr 2017 11:58

AW: Strategie für Propertyvergleich verschiedener Objecte
 
Ich gehe mal davon aus dass Json und Objektlisten damit an sich nichts zu tun haben. Du hast ein Objekt. Das Objekt hat Eigenschaften. Du möchtest mitbekommen wenn sich diese Eigenschaften ("Properties") ändern bzw. Werte aufweisen die aufgestellte Kriterien verletzen.

Verpasse doch den Property-Settern einfach das Prüfen auf ein Kriterium. Das Kriterium selbst ist ein Objekt bzw. Record. Hier einmal beispielhaft für Luftdruck und Temperatur, min und max.

Delphi-Quellcode:
uses
   System.SysUtils,
   System.Classes;

   TElementChangeCriteria = record
      /// <remarks>
      ///     <c>NaN</c> für "nicht vorhanden"
      /// </remarks>
      minTemperature:   Single;
      /// <remarks>
      ///     <c>NaN</c> für "nicht vorhanden"
      /// </remarks>
      maxTemperature:   Single;
      /// <remarks>
      ///     <c>NaN</c> für "nicht vorhanden"
      /// </remarks>
      minLuftdruck: Single;
      /// <remarks>
      ///     <c>NaN</c> für "nicht vorhanden"
      /// </remarks>
      maxLuftdruck: Single;

      public class function None(): TElementChangeCriteria; static;
   end;

   TElement = class
      private var
         FName:   String;
         FTemperatur: Single;
         FLuftdruck: Single;
      private
         procedure setTemperatur(const Value: Single);
         procedure setLuftdruck(const Value: Single);
      protected
         function criteriaMet(): Boolean; virtual;
         procedure checkEventCriteria();
      public var
         eventCriteria: TElementChangeCriteria;
         OnCriteriaEvent: TNotifyEvent;
      public
         property Name: String read FName;
         property Temperatur: Single read FTemperatur write setTemperatur;
         property Luftdruck: Single read FLuftdruck write setLuftdruck;
    end;

{ TElementChangeCriteria }

class function TElementChangeCriteria.None(): TElementChangeCriteria;
begin
   Result.minTemperature := Single.NaN;
   Result.maxTemperature := Single.NaN;
   Result.minLuftdruck := Single.NaN;
   Result.maxLuftdruck := Single.NaN;
end;

{ TElement }

procedure TElement.checkEventCriteria();
begin
   if criteriaMet() then
      if Assigned(OnCriteriaEvent) then OnCriteriaEvent(self);
end;

function TElement.criteriaMet(): Boolean;
begin
   if not eventCriteria.minTemperature.IsNan() then
      if (eventCriteria.minTemperature >= Temperatur) then Exit(True);
   if not eventCriteria.maxTemperature.IsNan() then
      if (eventCriteria.maxTemperature <= Temperatur) then Exit(True);

   if not eventCriteria.minLuftdruck.IsNan() then
      if (eventCriteria.minLuftdruck >= Luftdruck) then Exit(True);
   if not eventCriteria.maxLuftdruck.IsNan() then
      if (eventCriteria.maxTemperature <= Luftdruck) then Exit(True);

   Result := False;
end;

procedure TElement.setLuftdruck(const Value: Single);
begin
   FLuftdruck := Value;
   checkEventCriteria();
end;

procedure TElement.setTemperatur(const Value: Single);
begin
   FTemperatur := Value;
   checkEventCriteria();
end;
Ich persönlich finde dass gerade die Spring4D-Bibliothek viel mehr Spaß in die Sache bringt weil man hier vernünftige Multicast-Events hat und sich durch nullbare Datentypen dieses krumme "NaN" für die Fließkommazahlen sparen kann.


In Sachen Bedienung: Ich weiß nicht wie technik-affin deine Benutzer sind mit Querys wie "someCondition OR otherCondition AND finalCondition" kommen viele nicht gut zurecht. Ich würde einfach einen Frame mit Edit-Boxen und Text-Feldern machen der dann eine TElementChangeCriteria zurückgibt.

Hobbycoder 24. Apr 2017 12:19

QLb
 
Erst mal vielen Dank für deine Anregung.

Das ich als Trigger die Setter verwenden kann, das hatte ich auch schon vorgesehen.
Mir ging es ehr darum, wie ich die Menge an verschiedenen Kriterien komfortabel in eine Klasse packen könnte, so dass und/oder-Bedingungen unter diesen Kriterien auch noch möglich sind. (Vielleicht habe ich mich da im Ursprungsbeitrag etwas unglücklich ausgedrückt).

Meine Einzige Idee zur Zeit wäre, das ganze in eine String ala SQL-Syntax zu packen, und diesen bei Verwendung wieder zu parsen.
Das Userinterface würde ich ähnlich aufbauen, wie man das von Access kennt (Combobox zur Elementauswahl, Combobox zur Eigenschaftaufwahl, Combobox für Vergleichsoperator und Edit für die Bedingung).
Wenn jetzt alles Und-Verknüpfungen oder Oder-Verknüpfungen wären, dann wär's ja nicht so schwierig. Aber ich will ja, dass man die Möglichkeit hat das nach Belieben zu mischen. Und da kommen dann Klammern in Spiel, was die Sache für mich so kompliziert macht.

Und da auch nicht nur die Eigenschaften eines Elements untereinander als Kriterien verwendet werden, sondern alle Eigenschaften aller Elemente in einer Anfrage vorhanden sein können, kann ich zwar den Setter als Trigger verwenden, aber nicht innerhalbe des Elements gleiche die ganze Abfrage durchführen.
Deswegen will ich die Abfrage in separaten Klassen halten, und sie Setter der Elemente lösen einen Event aus, der seinerseits dann die Abfragen benachrichtigt, die ihrerseits dann bei Erfüllung wieder einen Event auslösen.
Mir geht es also um ein solches Klassendesign.

freimatz 25. Apr 2017 15:14

AW: Strategie für Propertyvergleich verschiedener Objecte
 
Na ja, irgendwie werde ich nicht so schlauf draus was du willst.
Einerseits ein Klassendesign, weiter oben gibt es ja schon einige Klassen.
Dann wiederum schreibst du von "String ala SQL-Syntax" und weiter von einem Userinterface ähnlich Access. Wenn ich das so lese dann braucht du kein Klassendesign sondern eine Architektur. Und wenn ich dann noch "Hobbycoder" sehe, weiß ich nicht mehr wie das zuammenpassen soll.

Hobbycoder 25. Apr 2017 16:05

AW: Strategie für Propertyvergleich verschiedener Objecte
 
Zitat:

Zitat von freimatz (Beitrag 1369041)
Na ja, irgendwie werde ich nicht so schlauf draus was du willst.
Einerseits ein Klassendesign, weiter oben gibt es ja schon einige Klassen.
Dann wiederum schreibst du von "String ala SQL-Syntax" und weiter von einem Userinterface ähnlich Access. Wenn ich das so lese dann braucht du kein Klassendesign sondern eine Architektur. Und wenn ich dann noch "Hobbycoder" sehe, weiß ich nicht mehr wie das zuammenpassen soll.

Ich weiß nicht was du mir mit diesem Post sagen willst.

a) ich habe oben EINE Beispielklasse gepostet, damit man erkennen kann in welcher Form die Daten vorliegen könnten.
b) Etwas Klassendesign kam von Günter
c) es geht ja gerade darum erst mal eine Idee zu entwickeln, solch Userdefiniete, parameterisierte Anfragen am besten zu hinterlegt, bzw. wie die Vergleichsalgorithmen sinnvoll in Klassen untergebracht werden können, um einfache und verschachtelte Algorithmen zu speichern. Und da könnte ein Syntax mit passendem Parser durchaus sinnvoll sein.
d) Da es Userdefiniert sein soll braucht es auch ein UI, das einfach verständlich ist. Das ist auch gut mit Punkt c zu vereinbaren.
e) Ich wüsste nicht was mein Nickname damit zu tun hätte. Schon erst mal gar nicht lässt dieser Rückschlüsse auf meine Person oder meine Qualifikation zu. (ich hätte da auch KaterKarlo oder MarcoCantu als Nick nehmen können. Hätte das was an deinem Kommentar geändert?)

Olli73 26. Apr 2017 11:11

AW: Strategie für Propertyvergleich verschiedener Objecte
 
Zitat:

Zitat von Hobbycoder (Beitrag 1369050)
c) es geht ja gerade darum erst mal eine Idee zu entwickeln, solch Userdefiniete, parameterisierte Anfragen am besten zu hinterlegt, bzw. wie die Vergleichsalgorithmen sinnvoll in Klassen untergebracht werden können, um einfache und verschachtelte Algorithmen zu speichern. Und da könnte ein Syntax mit passendem Parser durchaus sinnvoll sein.
d) Da es Userdefiniert sein soll braucht es auch ein UI, das einfach verständlich ist. Das ist auch gut mit Punkt c zu vereinbaren.

Anstatt aus dem UI einen "Text" zu machen und den anschließend zu parsen, könntest du direkt aus dem UI einen Binärbaum zur Auswertung erstellen. Wenn du dort Klassen verwendest und die Eigenschaften published machst, kannst du das auch so direkt abspeichern/laden.

freimatz 3. Mai 2017 11:02

AW: Strategie für Propertyvergleich verschiedener Objecte
 
Richtig. Und in dieem Fall braucht man dann keinen Parser mehr.
Bei "es geht ja gerade darum erst mal " hat es sich bei der professionellen Softwareentwicklung durchgesetzt erstmal abzuklären was der Kunde will. Natürlich ist es auch gut abzuschätzen was überhaupt geht. Und damit zu "Hobbycoder": es war nicht meine Absicht dein Können in Frage zu stellen. Aber dein Tag hat auch nur 24 Stunden. In meiner Firma haben wir einen Parser für solche Ausdrücke. Aus der Erfahrung halte ich sowas für etwas zu aufwendig für einen Hobbycoder.
Sorry wenn das nicht das ist was du hören willst (Kathinka rulez :))


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:00 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz