Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Verständnisproblem: Globale, gruppierte Konstanten (https://www.delphipraxis.net/181169-verstaendnisproblem-globale-gruppierte-konstanten.html)

Keks 21. Jul 2014 19:21

Delphi-Version: XE

Verständnisproblem: Globale, gruppierte Konstanten
 
Ich benötige in meiner Software regelmäßig gewisse Werte, die stets gleich bleiben sollen und sich in einer Ini Datei speichern lassen.
Die Werte sollten zudem irgendwie gruppiert sein, damit man damit leichter arbeiten kann (Autovervollständigung, Parameter-Eingrenzung).

So eine Liste ist zwar oft sehr praktisch und per
Delphi-Quellcode:
Ord()
lässt sich auch ein speicherbarer Wert ableiten, aber wenn ich die Liste später irgendwann verändere, ist es unmöglich, neue Werte zwischenrein zu setzen, da sich sonst die Zählnummer ändert.
Delphi-Quellcode:
TTier = (tiHund, tiKatze, tiMaus)


Um den Werten speicherbare Zahlen zuzuordnen, dachte ich stattdessen an sowas:
Delphi-Quellcode:
  TTier = record
    const HUND = 0;
    const KATZE = 12;
    const MAUS = 5;
  end;
Leider bin ich mir noch etwas unschlüssig, ob Records wirklich der beste Weg dafür sind oder ob es eine noch bessere Möglichkeit gibt.
Ich weiß, dass ich das auch als Klasse/Objekt lösen kann. Aber irgendwie fände ich es seltsam, für jede Wertegruppe ein globales Objekt zu erzeugen, das nur konstante Werte bereithält!?

Schön wäre es z.B., wenn man damit auch die Parameter-Typen in Funktionen festlegen könnte.
Also etwa sowas:
Delphi-Quellcode:
function GetTiername(tn: TTier): String;

Mit Aufruf:
Delphi-Quellcode:
s := GetTiername(TTier.HUND);

Das geht aber natürlich nicht, weil dann ein vollständiges Record und nicht ein einfacher Wert erwartet wird. Ändert man den Parameter in Integer, geht der Aufruf, aber die Funktion lässt sich dann natürlich auch mit allen anderen Integern und nicht nur den TTier-Werten aufrufen.

Zudem weiß ich leider nicht, ob es OK ist, direkt auf die Record-Werte zuzugreifen (
Delphi-Quellcode:
TTier.HUND
) oder ob man das besser erst instanzieren sollte (
Delphi-Quellcode:
var Tier: TTier; {...} Tier.HUND
)

Ich würde mich freuen, wenn Ihr mir hier etwas auf die Sprünge helfen würdet. Danke!

himitsu 21. Jul 2014 19:26

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Zitat:

Zitat von Keks (Beitrag 1266241)
So eine Liste ist zwar oft sehr praktisch und per
Delphi-Quellcode:
Ord()
lässt sich auch ein speicherbarer Wert ableiten, aber wenn ich die Liste später irgendwann verändere, ist es unmöglich, neue Werte zwischenrein zu setzen, da sich sonst die Zählnummer ändert.

Man kann über die RTTI den einen Enum oder Set auch problemlos in einen String übersetzen lassen. (siehe die Enums/Sets in Property, welche in der DFM gespeichert werden)

Diese RTTI-Daten kann man kann auch problemlos verwenden, um damit die Autovervollständigung zu füttern.

Constanten stehen nicht in der RTTI, also lassen sie sich nicht automatisch auslesen und du bräuchstest somit eine manuell erstellte Liste/Array mit den Werten, um sie in der Autovervollständigung nutzen zu können. (siehe die TColor-Konstanten) Diese Liste kann auch über eine Registrierungsfunktion zur Laufzeit (z.B. beim Programmstart) gefüllt werden.

Keks 21. Jul 2014 19:43

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Zitat:

Zitat von himitsu (Beitrag 1266242)
RTTI

Nach dem Wechsel zu Delphi XE vor einigen Jahren war ich über den Größenzuwachs der kompilierten Exe erschrocken. Nach ein paar Recherchen war klar, dass hauptsächlich RTTI daran Schuld ist. Ich habe daraufhin alles mögliche getan, um es möglichst rauszunehmen, sodass sich die Dateigröße dann deutlich wieder reduzierte. Ich weiß nicht, ob ich das jetzt alles wieder rückgängig machen möchte...

Zitat:

Zitat von himitsu (Beitrag 1266242)
siehe die TColor-Konstanten

Was meinst Du genau? In Graphics.pas werden die Farben normalen Konstanten zugewiesen.
Meinst Du ich soll das so ähnlich machen?
Delphi-Quellcode:
type
  TTier = -$7FFFFFFF-1..$7FFFFFFF;
const
  tiKatze = TTier($00000C);

himitsu 21. Jul 2014 20:13

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Keine Sorge, selbst wenn man die neue erweiterte RTTI fast komplett deaktiviert (was möglich ist), dann funktioniert das immernoch, da diese Funktion auf die alte RTTI aufbaut, welche es schon praktisch immer gibt, da sie von der VCL (FormDesigner) rege verwendet wird.

http://geheimniswelten.de/tipps/code...und-zu-string/
GetEnumName und SetToString (Unit TypInfo), bzw. besser und vorallem (typ)sicherer hinter den Generics versteckt.


Und ich meinte das Colors-Array, welches sich aktuell in UIConsts versteckt und das z.B. von ColorToString verwendet wird.
Natürlich ist dieses Array fest, so daß man (eigentlich) keine eigenen TColor-Konstanten in den DFM-Loader einschleußen kann.

Perlsau 21. Jul 2014 20:44

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Wieso eine Ini-Datei, wenn es sich doch angeblich um immer gleichbleibende Konstanten handelt? Konstanten wird gewöhnlich ein Wert im Programmcode zugewiesen. Weist du Variablen Werte aus einer Ini-Datei zu, sind das keine Konstanten, sondern eben Variablen, auch wenn diese im gesamten Programmverlauf weitgehend konstant bleiben (sollen), wie z.B. ein Datenbank-Pfad oder der Benutzername usw. Deshalb unterscheidet Delphi doch Konstanten und Variablen, deren Deklaration mit unterschiedlichen Tokens eingeleitet wird: Const und Var.

Keks 21. Jul 2014 21:33

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Zitat:

Zitat von Perlsau (Beitrag 1266257)
Wieso eine Ini-Datei, wenn es sich doch angeblich um immer gleichbleibende Konstanten handelt? Konstanten wird gewöhnlich ein Wert im Programmcode zugewiesen. Weist du Variablen Werte aus einer Ini-Datei zu, sind das keine Konstanten, sondern eben Variablen, auch wenn diese im gesamten Programmverlauf weitgehend konstant bleiben (sollen), wie z.B. ein Datenbank-Pfad oder der Benutzername usw. Deshalb unterscheidet Delphi doch Konstanten und Variablen, deren Deklaration mit unterschiedlichen Tokens eingeleitet wird: Const und Var.

Letztlich geht es darum, dass der Anwender irgendwelche Auswahlen im Programm trifft, die gespeichert und wieder geladen werden müssen. Um bei dem Beispiel mit den Tieren zu bleiben: Der Anwender wählt selektiert in einer Liste mehrere Tiere. Diese Selektion muss auch später noch geladen und ausgewertet werden können. Es reicht nicht, die Indizes zu speichern, weil sich die Liste jederzeit ändern kann. Un in anderen Fällen brauche ich auch ganz bestimmte Werte, um konsistent mit anderen Programmen, auf die ich keinen Einfluss habe, zu bleiben (wenn man sich eine Datenquelle teilt). Ob das nun Ini- oder DB-Einträge sind, spielt eigentlich keine Rolle.

Sir Rufo 21. Jul 2014 21:56

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Das was du meinst ist wohl ein Bei Google suchenValueObject.

Ein Beispiel (zwar PHP sollte aber aussagekräftig genug sein) für Währungen findest du unter
https://github.com/sebastianbergmann...c/Currency.php

Perlsau 22. Jul 2014 02:26

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Zitat:

Zitat von Keks (Beitrag 1266269)
Letztlich geht es darum, dass der Anwender irgendwelche Auswahlen im Programm trifft, die gespeichert und wieder geladen werden müssen. Um bei dem Beispiel mit den Tieren zu bleiben: Der Anwender wählt selektiert in einer Liste mehrere Tiere. Diese Selektion muss auch später noch geladen und ausgewertet werden können. Es reicht nicht, die Indizes zu speichern, weil sich die Liste jederzeit ändern kann. Un in anderen Fällen brauche ich auch ganz bestimmte Werte, um konsistent mit anderen Programmen, auf die ich keinen Einfluss habe, zu bleiben (wenn man sich eine Datenquelle teilt). Ob das nun Ini- oder DB-Einträge sind, spielt eigentlich keine Rolle.

Die Speicherung habe ich nicht thematisiert, sondern deine Verwendung des Begriffs "Konstante", wo du doch eigentlich "Variable" meintest.

nuclearping 22. Jul 2014 03:48

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Du kannst auch sowas machen:
Delphi-Quellcode:
TTier = (tiHund = 1, tiKatze = 27, tiMaus = 15, ...)

Dejan Vu 22. Jul 2014 05:43

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Zitat:

Zitat von Perlsau (Beitrag 1266288)
Die Speicherung habe ich nicht thematisiert, sondern deine Verwendung des Begriffs "Konstante", wo du doch eigentlich "Variable" meintest.

Deutsche Sprache <> Delphi. :roll:
In der deutschen Sprache sind Interpretationen Gott-Sei-Dank erlaubt. Ich definiere eine 'Konstante' übrigens als Wert, der im Anwendungskontext nicht verändert wird. Diese Interpretation lässt mir die Freiheit, in einer Spezifikation den Terminus 'Konstante' zu verwenden, ohne gerichtlich einklagbar darauf drängen zu müssen, das dieser Wert im Code auch als 'CONST' deklariert werden muss. Es reicht, wenn er während des Lebenszyklus der Anwendung nicht veränderbar ist, und das schließt initiales Laden aus. Gleichzeitig verbaue ich mir damit nicht die Möglichkeit des initialen Ladens. Aber wenn Du dich dran reibst, dann wende dich an Emba:
Delphi-Quellcode:
Const
  IAmNotAConstant : Integer = 3;

begin
{$J+}
  IAmNotAConstant := 4; // Verbooooten !!!1!!!!11!!!EINS!!!11!!ELF!!!
Im Übrigen bin ich auch für korrekte Terminologie, aber nur, wenn es um wichtige Dinge geht. Auch kann ich verstehen, das in der reinen Sprachenlehre eine Konstante nicht immer eine Konstante ist. Aber dann ist sie eigentlich auch keine Variable, denn verändert wird sie nicht (nur initialiert).
Zitat:

Zitat von Heraklit von Ephesus
Die einzige Konstante im Universum ist die Veränderung.

Zum Thema: Ich hätte da noch statische Klasseneigengeschaften anzubieten. Bei Applikationskonstanten etwa so:
Delphi-Quellcode:
Type
Unit ApplicationSettings;
Interface
Type
  TApplicationContext = Class
  private
    class var fMySetting : string;
    class var fSomeOtherValue : Integer;
    class procedure Load();
  public
    Class property MySetting : String read fMySetting;
    class property SomeOtherValue : Integer read fSomeOtherValue;

  end;
...
implementation

...
initialization
  TApplicationContext.Load();
end.
Diese Unit bindest Du einfach immer dann ein, wenn Du Zugriff auf die Applikationskonstanten benötigst. Du hast hier dann alles, was Du brauchst. Damit wäre deine erste Vorgabe erfüllt:
Zitat:

Die Werte sollten zudem irgendwie gruppiert sein, damit man damit leichter arbeiten kann (Autovervollständigung, Parameter-Eingrenzung).
Für dein konkretes Beispiel der Tiere (das nur bedingt etwas mit dem generellen Problem der Applikationskonstanten zu tun hat) sollte man zunächst klarstellen, das die einzelnen Tiere eindeutige Identifikatoren (Id) besitzen, die eben nicht änderbar sind (also eine Perlsau'sche Konstante). Hier hat man immer das Dilemma, das man einfach darauf hoffen muss, das sich die Anwendungen an die Konvention halten, einem Hund immer die ID 1 zuzuweisen usw.
Ich würde meine TTier-Klasse wie folgt umsetzen, und dabei die von Sir Rufo vorgeschlagenen value objects einsetzen. Die Methode 'GetTierName' gehört dann zum Tier (OOP) und ist keine isolierte Funktion (PP)
Delphi-Quellcode:
Type
  TTier = class
  private
    fID: Integer;
    fName : String;
    class var fKatze: TTier;
    class var fHund: TTier;
    class procedure Load;
    constructor Create (aID : Integer; Name : String);
  public
    property ID : Integer read fID;
    property Name : String read fName;

    class property Hund : TTier Read fHund;
    class property Katze : TTier Read fKatze;
  end;

{ TTier }

constructor TTier.Create(aID: Integer);
begin
  fID := aID;
end;

class procedure TTier.Load;
begin
// Natürlich wird hier aus einer Datei/Registry/Datenbank geladen
  fHund := TTier.Create(3,'Hund');
  fKatze := TTier.Create(4,'Mitzekatze');
end;

initialization
  TTier.Load;
end.
Und damit solltest Du alle deine Wünsche umsetzen können, denn eine Katze ist ein Tier, konstant, die Id ist Perlsau-konform (sofern man die Datei nicht verändert, siehe Heraklit) und deine Tiere können um Methoden und Eigenschaften erweitert werden, was bei einem Enum nicht geht. Ich persönlich halte auch nicht viel von RTTI-Geraffel im Hintergrund.

Sir Rufo 22. Jul 2014 07:25

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Hier ein ValueObject in Aktion:
Delphi-Quellcode:
program dp_181169;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils,
  Tier in 'Tier.pas';

procedure Test;
var
  LTier : TTier;
begin
  for LTier in TTier._All do // <- alle Tiere anzeigen
    begin
      WriteLn( LTier.name );
    end;

  LTier := TTier.Create( 5 ); // <- erzeugen mit einer TierId
  try
    if LTier.Equals( TTier.Hund ) // <- vergleichen mit Hund
    then
      WriteLn( 'Wie ein/e ' + TTier.Hund.name );
    if LTier.Equals( TTier.Katze ) // <- vergleichen mit Katze
    then
      WriteLn( 'Wie ein/e ' + TTier.Katze.name );
    if LTier.Equals( TTier.Maus ) // <- vergleichen mit Maus
    then
      WriteLn( 'Wie ein/e ' + TTier.Maus.name );
  finally
    LTier.Free; // <- Instanz wird entfernt
  end;

  LTier := TTier.Hund; // <- Instanz über Klassen-Eigenschaft
  try
    WriteLn( 'Hier ist ein/e ', LTier.name );
  finally
    LTier.Free; // <- macht nichts
  end;

  WriteLn( 'Hier ist immer noch ein/e ', LTier.name ); // <- Kein Problem

  FreeAndNil( LTier ); // <- wird nur auf nil gesetzt

  LTier := TTier.Create( 0815 ); // <- Exception, weil ungültige TierId

end;

begin
  ReportMemoryLeaksOnShutdown := True;
  try
    Test;
  except
    on E : Exception do
      WriteLn( E.ClassName, ': ', E.Message );
  end;
  ReadLn;

end.
und die Ausgabe
Code:
Hund
Katze
Maus
Wie ein/e Maus
Hier ist ein/e Hund
Hier ist immer noch ein/e Hund
EArgumentOutOfRangeException: Ungültige TierId
Ein robustes ValueObject bedarf unter Delphi allerdings einiges an zusätzlichem Gebimmel-Bammel, da wir ja auf die lifetime der Instanzen achtgeben müssen.

Dafür kann aber auch der DAP (Dümmste Anzunehmende Programmierer) es niemals schaffen eine ungültige Instanz dieses ValueObjects zu erzeugen (solange er den Source dieser Klasse nicht anfasst).

Ob die einzelnen möglichen Werte direkt in der Klasse/im Quelltext hinterlegt werden hängt hierbei immer vom jeweiligen Kontext/Einsatzgebiet ab.

Wenn neue mögliche Werte hinzukommen und diese auch noch eine weitere Berücksichtigung in der Anwendung benötigen, dann baut man die Werte tatsächlich fest ein (Diese Anwendung kann halt nur mit Hund, Katze, Maus umgehen, aber nicht mit dem neu hinzugekommen Elefanten, dazu muss noch mehr angepasst werden).
Delphi-Quellcode:
unit Tier;

interface

uses
  System.Generics.Collections;

type
  TValueObject = class abstract
  public
    function SameValueAs( Other : TValueObject ) : Boolean; virtual; abstract;
    function Equals( Obj : TObject ) : Boolean; override;
  end;

  TTier = class( TValueObject )
{$REGION 'values'}
  private type
    TValue = record
      Id : Integer;
      Name : string;
    end;

  const
    _Values : array [0 .. 2] of TValue = ( ( Id : 0; name : 'Hund' ), ( Id : 12; name : 'Katze' ), ( Id : 5;
        name : 'Maus' ) );
    class procedure BuildItems;
{$ENDREGION}
{$REGION 'class'}
  private
    class var _Items : TList<TTier>;
    class var _ItemsDict : TDictionary<Integer, TTier>;
    class var _Shutdown : Boolean;
    class function GetTier( const Index : Integer ) : TTier; static;
    class function GetAll : TArray<TTier>; static;
  protected
    class constructor Create;
    class destructor Destroy;
  public
    class property _All : TArray<TTier> read GetAll;
    class property Hund : TTier index 0 read GetTier;
    class property Katze : TTier index 12 read GetTier;
    class property Maus : TTier index 5 read GetTier;
{$ENDREGION}
{$REGION 'instance'}
  private
    FId : Integer;
    FName : string;
    function SameTierAs( Other : TTier ) : Boolean;
    constructor CreateItem( );
{$ENDREGION}
  public
    constructor Create( TierId : Integer );
    destructor Destroy; override;

    function SameValueAs( Other : TValueObject ) : Boolean; override;
    function GetHashCode : Integer; override;
    function ToString : string; override;
    procedure FreeInstance; override;

    property Id : Integer read FId;
    property name : string read FName;

  end;

implementation

uses
  System.SysUtils;

{ TValueObject }

function TValueObject.Equals( Obj : TObject ) : Boolean;
begin
  Result := ( Self = Obj ) or Assigned( Obj ) and ( Self.ClassType = Obj.ClassType ) and
    SameValueAs( Obj as TValueObject );
end;

{ TTier }

class procedure TTier.BuildItems;
var
  LValue : TValue;
  LItem : TTier;
begin
  if Assigned( _ItemsDict )
  then
    Exit;

  _Items := TObjectList<TTier>.Create( True );
  _ItemsDict := TDictionary<Integer, TTier>.Create( );

  for LValue in _Values do
    begin
      LItem := Self.CreateItem;
      LItem.FId := LValue.Id;
      LItem.FName := LValue.Name;
      _Items.Add( LItem );
      _ItemsDict.Add( LValue.Id, LItem );
    end;
end;

constructor TTier.Create( TierId : Integer );
begin
  inherited Create;
  if not _ItemsDict.ContainsKey( TierId )
  then
    raise EArgumentOutOfRangeException.Create( 'Ungültige TierId' );
  FId := TierId;
  FName := _ItemsDict[TierId].Name;
end;

constructor TTier.CreateItem;
begin
  inherited;
end;

class constructor TTier.Create;
begin
  BuildItems;
end;

destructor TTier.Destroy;
begin
  if _Items.Contains( Self ) and not _Shutdown
  then
    Exit;
  inherited;
end;

procedure TTier.FreeInstance;
begin
  if _Items.Contains( Self ) and not _Shutdown
  then
    Exit;
  inherited;
end;

class function TTier.GetAll : TArray<TTier>;
begin
  Result := TTier._Items.ToArray;
end;

function TTier.GetHashCode : Integer;
begin
  Result := FId;
end;

class function TTier.GetTier( const Index : Integer ) : TTier;
begin
  Result := TTier._ItemsDict[index]
end;

class destructor TTier.Destroy;
begin
  TTier._Shutdown := True;
  TTier._ItemsDict.Free;
  TTier._Items.Free;
end;

function TTier.SameTierAs( Other : TTier ) : Boolean;
begin
  Result := Assigned( Other ) and ( Self.FId = Other.FId );
end;

function TTier.SameValueAs( Other : TValueObject ) : Boolean;
begin
  Result := ( Self = Other ) or Assigned( Other ) and ( Self.ClassType = Other.ClassType ) and
    SameTierAs( Other as TTier );
end;

function TTier.ToString : string;
begin
  Result := FName;
end;

end.

himitsu 22. Jul 2014 08:07

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Zitat:

Zitat von nuclearping (Beitrag 1266289)
Du kannst auch sowas machen:
Delphi-Quellcode:
TTier = (tiHund = 1, tiKatze = 27, tiMaus = 15, ...)

Hier sollte man aber wissen, daß die RTTI so nicht mehr funktioniert, da hierbei die NamensListe der einzelnen Werte nicht mehr gespeichert wird.

Man kann hier dafür den ordinalen Wert speichern und nahezu beliebig festlegen,
aber Namen nur noch über eine selbst definierte Liste. (nicht aus der RTTI auslesbar)

TiGü 22. Jul 2014 08:46

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Uiuiui, da wird wieder mit den dicksten Kanonen auf kleinste Spatzen geschossen!

Die Idee von Nuclearping ist die simpelste und wahrscheinlich am schnellsten umsetzbare Lösung.

Ggf. kann man das noch per Pseudonamespaces und Klassen schöner verpacken:

Delphi-Quellcode:
  TLifeForms = class
  public type
    TAnimal = class
    public type
      TMammal = (Dog = 1, Cat = 27, Mouse = 15);
    end;

    TPlants = class
    public type
      TRoses = (DogRose = 23, RugosaRose = 58);
    end;
  end;

Sir Rufo 22. Jul 2014 09:36

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Zitat:

Zitat von TiGü (Beitrag 1266300)
Uiuiui, da wird wieder mit den dicksten Kanonen auf kleinste Spatzen geschossen!

Die Idee von Nuclearping ist die simpelste und wahrscheinlich am schnellsten umsetzbare Lösung.

Schnell und simpel ja, allerdings hat man nicht die gesamte Vereinbarung (wie hier mit einem externen System) in einem Objekt gekapselt und auch das Erzeugen über eine Id ist umständlicher.

Hier wird auch ein sehr simples Beispiel angeführt. In der Realität sind diese ValueObjects aber wesentlich komplexer (z.B. Währung). Teilweise können diese Werte weggelassen werden, weil kein Pflichtfeld und sind dann einfach
Delphi-Quellcode:
nil
oder bekommen einen Dummy-Wert zugewiesen (TTier.KeinTier) oder es wird nicht übergeben und dann wird automatisch der Dummy-Wert zurückgegeben.

Es ist dann schön, wenn man ein Konzept hat, was alle diese Anforderungen erfüllen kann und die Handhabung immer gleich ist.

Auch kann man ValueObjects (egal welchen Typs) einfach in eine Liste (z.B. Tags) packen.
Delphi-Quellcode:
TSomeObject = class
private
  FTags : TList<TValueObject>;
public
  procedure AddTag( ATag : TValueObject );
end;

SomeObject.Add( TTier.Create(5) );
SomeObject.Add( TColorInfo.Create( clRed ) );
...
Das die Klasse aufwändig ist und nicht zu den schnell mal eben hingetippten zählt ist mir durchaus bewusst, allerdings auch die Flexibilität und die Abgeschlossenheit in sich und ich kann mich jederzeit darauf verlassen, dass nur valide Werte ankommen.

Es hängt vom Einsatzgebiet und den zu erwartenden Erweiterungen ab ob ich so etwas ins Rennen bringe, je komplexer das System umso eher nehme ich solche Konstrukte.

TiGü 22. Jul 2014 11:15

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Zitat:

Zitat von Sir Rufo (Beitrag 1266302)
Hier wird auch ein sehr simples Beispiel angeführt.

Es hängt vom Einsatzgebiet und den zu erwartenden Erweiterungen ab ob ich so etwas ins Rennen bringe, je komplexer das System umso eher nehme ich solche Konstrukte.

Also nichts gegen deine Lösung, die finde ich sehr gut und interessant.
Sie hat bei komplexen Systemen ihre Daseinsberechtigung.

Aber hier haben wir es (bisher) mit ein paar Enum-Werten zu tun, die in eine Ini-Datei gespeichert werden sollen.
Wie die eigentlichen Umstände in Keks' Programm sind, wissen wir nicht.

Von daher ist das YAGNI-Prinzip anzuwenden.

Keks 22. Jul 2014 11:25

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Wow, Ihr seid super!! :spin2:
Wieder einiges dazugelernt.

Für meinen aktuellen Fall ist das hier wohl wirklich das beste (natürlich nicht zuletzt, weil es simpel, schnell umsetzbar und kompakt/übersichtlich ist):
Zitat:

Zitat von nuclearping (Beitrag 1266289)
Du kannst auch sowas machen:
Delphi-Quellcode:
TTier = (tiHund = 1, tiKatze = 27, tiMaus = 15, ...)

Ich hatte in meinem Eingangsposting ja schon erwähnt, dass ich Aufzählungen grundsätzlich sehr sympatisch finde. Aber ich wusste bis dato nicht, dass man die Indizes darin vorgeben kann (irgendwie bin ich gar nicht auf die Idee gekommen, dass das gehen könnte). Das ist super! Damit funktioniert alles, was ich für den Einsatzzweck benötige. Sogar mit schönen Nebeneffekten, dass z.B. case-Blöcke automatisch mit allen Werten erzeugt werden.

Zitat:

Zitat von Dejan Vu (Beitrag 1266290)
Zitat:

Zitat von Perlsau (Beitrag 1266288)
Die Speicherung habe ich nicht thematisiert, sondern deine Verwendung des Begriffs "Konstante", wo du doch eigentlich "Variable" meintest.

Deutsche Sprache <> Delphi. :roll:
In der deutschen Sprache sind Interpretationen Gott-Sei-Dank erlaubt. Ich definiere eine 'Konstante' übrigens als Wert, der im Anwendungskontext nicht verändert wird.

Danke, so meinte ich das auch. :)

Zitat:

Zitat von himitsu (Beitrag 1266250)
Keine Sorge, selbst wenn man die neue erweiterte RTTI fast komplett deaktiviert (was möglich ist), dann funktioniert das immernoch [...]

Ich habe mich gestern Nacht nochmal ein wenig in RTTI eingelesen, aber es ist mir nach wie vor "suspekt". Sorry. ;)

Zitat:

Zitat von Sir Rufo (Beitrag 1266302)
Schnell und simpel ja, allerdings hat man nicht die gesamte Vereinbarung (wie hier mit einem externen System) in einem Objekt gekapselt

In dem speziellen Fall, den ich gerade vor mir habe, kenne ich die Werte schon vorher, muss sie also nicht dynamisch aus der externen Datenquelle zuordnen. Ich muss aber sehr wohl diese Werte einhalten, wenn ich die Daten interpretiere bzw. abspeichere.
Ich muss aber sagen, dass ich die empfohlenen ValueObjects für einen anderen Einsatzzweck, den ich demnächst angehen werde, interesasnt finde. Dort werde ich das etwas komplexer benötigen und da sieht Dein ausführliches Beispiel (Danke!) für mich sehr passend aus.

Ich habe mir mal ein Lesezeichen für diesen Thread gesetzt und werde da sicherlich später für andere Anwendungsfälle wieder nachschlagen. :)

Sir Rufo 22. Jul 2014 15:52

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Zitat:

Zitat von Keks (Beitrag 1266314)
Zitat:

Zitat von Sir Rufo (Beitrag 1266302)
Schnell und simpel ja, allerdings hat man nicht die gesamte Vereinbarung (wie hier mit einem externen System) in einem Objekt gekapselt

In dem speziellen Fall, den ich gerade vor mir habe, kenne ich die Werte schon vorher, muss sie also nicht dynamisch aus der externen Datenquelle zuordnen. Ich muss aber sehr wohl diese Werte einhalten, wenn ich die Daten interpretiere bzw. abspeichere.

In meinem Beispiel gibt es auch keine externe Datenquelle, von daher sehe ich das jetzt mal nicht als Gegenargument.

Und YAGNI verletze ich damit auch nicht, denn die Klasse macht nur das, was von ihr aktuell gefordert wird:
  • Nur die vorgegebenen Werte zulassen
  • Alle möglichen Werte für eine Auswahl (ComboBox) einfach vorhalten
Bei der Benutzung der Klasse ist ein großer Teil des Drumherums nur dafür da, dass die vorgehaltenen Instanzen nicht von aussen aus Versehen freigegeben werden können und somit die Benutzung intuitiv erfolgen kann ohne sich einen Kopf machen zu müssen (mit ARC würde die Klasse wesentlich kompakter aussehen).

Zudem ist eben die gesamte Vereinbarung enthalten (Interpretation des externen Systems über Integer, Bedeutung für Programmierer/Benutzer als Eigenschaftsname bzw. String) und nicht auf mehrere Stellen verteilt und zur Darstellung benötige ich keine weiteren Hilfsroutinen um z.B. zu einem Integer/Enum einen aussagekräftigen Text zu bekommen. Denn dass 0 hier Hund bedeutet gibt das externe System vor, und dann doch besser an einer Stelle definieren.

Keks 22. Jul 2014 17:37

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Zitat:

Zitat von Sir Rufo (Beitrag 1266343)
In meinem Beispiel gibt es auch keine externe Datenquelle, von daher sehe ich das jetzt mal nicht als Gegenargument.

Das sollte kein Gegenargument werden, sondern eine Anmerkung zur Einschränkung einer Enumeration. Ein ValueObject ist hier flexibler, denn hier könnte man die Werte auch dynamisch festlegen. Ich wollte damit nur sagen, dass ich dies in meinem Fall kein Entscheidungskriterium war.

Sir Rufo 22. Jul 2014 18:17

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Zitat:

Zitat von Keks (Beitrag 1266361)
Zitat:

Zitat von Sir Rufo (Beitrag 1266343)
In meinem Beispiel gibt es auch keine externe Datenquelle, von daher sehe ich das jetzt mal nicht als Gegenargument.

Das sollte kein Gegenargument werden, sondern eine Anmerkung zur Einschränkung einer Enumeration. Ein ValueObject ist hier flexibler, denn hier könnte man die Werte auch dynamisch festlegen. Ich wollte damit nur sagen, dass ich dies in meinem Fall kein Entscheidungskriterium war.

Ok :)

Dejan Vu 23. Jul 2014 06:12

AW: Verständnisproblem: Globale, gruppierte Konstanten
 
Ich hatte die Aufgabenstellung nicht so verstanden, das nur ein paar Enumwerte gespeichert/gelesen werden sollen. Aber wenn das alles ist, dann ist die banale, naheliegenste und einfachste Lösung von Nuclearping natürlich zu verwenden.


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:21 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