![]() |
Record im Array nutzen? - Sinnvollere Wege?
Guten Tag,
zurzeit benutze ich ein Array, welches ein Element eines Records ist. Nur habe ich gerade bei meinen Recherchen erfahren, dass dies keine schöne Methode ist. Also mein Record sieht so aus:
Delphi-Quellcode:
Das Array besteht aus 40 Feldern, die jeweils ja diese Record Anordnung haben.
TEmployee = Record
CardID : Integer; Prename, Surname, Workstation, Position : String[100]; Birthdate : TDate; AvailAbility : Array[1..7] of String; End; Nun Frage ich mich, ist dieser Weg, wie ich ihn gewählt habe, in Ordnung, oder gibt es bessere Methoden dies umzusetzen? MfG Asura |
AW: Record im Array nutzen? - Sinnvollere Wege?
Wie wäre es mit Objekten in einer TObjectList?
Also TEmployee = class und die Liste je nach Delphiversion deklariert als TObjectList oder wenn möglich besser TObjectList<TEmployee>. Vorteile sind, dass du Teile der Objekte anders als bei Records auch direkt setzen kannst über die Liste und dass du eine beliebige Anzahl an Elementen hast ohne das Array manuell in der Größe verändern zu müssen. |
AW: Record im Array nutzen? - Sinnvollere Wege?
Eine Liste ist zunächst einmal eine gute Alternative.
Ich würde aber erst einmal tiefer ansetzen und die Elemente des Records kritisch hinterfragen. a) ist die CardId wirklich numerisch? oder sieht sie nur so aus? b) was verbirgt sich hinter Position? wenn dies festgelegte Inhalte sind, dann wäre es nicht schlecht z.B. mit ENUM-Typen zu arbeiten. sonst läuft die Suche nach "Hausmeister" ins Leere weil da jetzt der "Facility Manager" steht. c) Wenn Du
Delphi-Quellcode:
nutzt dann wenigstens auch
Position : String[100];
Delphi-Quellcode:
oder
AvailAbility : Array[1..7] of AnsiString;
Delphi-Quellcode:
Sonst ist das Character-Chaos vorprogrammiert.
AvailAbility : Array[1..7] of String[255];
Gruß K-H |
AW: Record im Array nutzen? - Sinnvollere Wege?
Ich habe die schreckliche Vermutung dass sich hinter Availability die Verfügbarkeit an einem bestimmten Wochentag verbirgt. Hier wäre ja dann wohl eher so etwas sinnvoll (abgesehen dass es dann in 8 Bit statt in 8 Byte gespeichert werden kann):
Delphi-Quellcode:
TWeekDays = (wdMonday, wdTuesday, wdWednesday, wdThursday, wdFriday, wdSaturday, wdSunday);
TAvailability = set of TWeekDays; |
AW: Record im Array nutzen? - Sinnvollere Wege?
Hallo,
Dankeschön erstmal für die Antworten. Ich habe mal im Anhang das ganze Projekt angehängt, sodass ihr euch mal ein Bild machen könnt (Im Source Ordner zu finden). Ich habe es zurzeit über meine Methode gelöst - zwar mit mehreren Stunden Ärgernissen, aber schlussendlich gelöst. Aber auch nur die Mitarbeiterverwaltung zum großteil. Zu den Availability: Ja das sind Tage. Ich habe das so gelöst, dass der Index 1 Beispielsweise für Montag steht und der hintergelegte Text "17:00-23:00" beispielsweise gesplittet und aufgeteilt wird. Alle Werte sollten Variabel gehalten werden, sprich in meiner aktuellen Version lassen sich alle bearbeiten. Auch Position. Und Card ID benutze ich zum Teil dafür um meine Items im Array zu finden, sie dient aber auch für den Anwender Informationsgrundlage, die bei der Eintragung wichtig ist. Ich würde mich auch sehr freuen, wenn ihr generell paar Kritik Äußerungen zu den Programmcode mir schreiben könntet und was ich da verbessern kann oder komplett verändern muss. Würde mich sehr freuen! MfG Asura |
AW: Record im Array nutzen? - Sinnvollere Wege?
Ich hätte das mit Klassen so aufgebaut
Delphi-Quellcode:
unit Unit1;
interface uses System.Classes, System.DateUtils, System.Generics.Collections, System.TimeSpan; type {$SCOPEDENUMS ON} TWeekDay = ( Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday ); {$SCOPEDENUMS OFF} TAvailibility = class( TPersistent ) private FFrom: TTime; FDuration: TTimeSpan; FIsAvailable: Boolean; procedure SetFrom( const Value: TTime ); procedure AssignToAvailibility( Dest: TAvailibility ); procedure SetIsAvailable( const Value: Boolean ); protected procedure AssignTo( Dest: TPersistent ); override; public function Equals( Obj: TObject ): Boolean; override; property IsAvailable: Boolean read FIsAvailable write SetIsAvailable; property From: TTime read FFrom write SetFrom; property Duration: TTimeSpan read FDuration write FDuration; end; TEmployee = class( TPersistent ) private FAvailibility: TObjectDictionary<TWeekDay, TAvailibility>; FCardID: Integer; FPrename: string; FSurname: string; FWorkstation: string; FPosition: string; FBirthday: TDate; function GetAvailibility( Weekday: TWeekDay ): TAvailibility; procedure SetBirthday( const Value: TDate ); procedure AssignToEmployee( Dest: TEmployee ); procedure SetAvailibility( Weekday: TWeekDay; const Value: TAvailibility ); protected procedure AssignTo( Dest: TPersistent ); override; public constructor Create; destructor Destroy; override; function Equals( Obj: TObject ): Boolean; override; property CardID: Integer read FCardID write FCardID; property Prename: string read FPrename write FPrename; property Surname: string read FSurname write FSurname; property Workstation: string read FWorkstation write FWorkstation; property Position: string read FPosition write FPosition; property Birthday: TDate read FBirthday write SetBirthday; property Availibility[ Weekday: TWeekDay ]: TAvailibility read GetAvailibility write SetAvailibility; end; implementation { TEmployee } procedure TEmployee.AssignTo( Dest: TPersistent ); begin if ( Dest is TEmployee ) then AssignToEmployee( Dest as TEmployee ) else inherited; end; procedure TEmployee.AssignToEmployee( Dest: TEmployee ); var LWeekDay: TWeekDay; begin Dest.FCardID := Self.FCardID; Dest.FPrename := Self.FPrename; Dest.FSurname := Self.FSurname; Dest.FWorkstation := Self.FWorkstation; Dest.FPosition := Self.FPosition; Dest.FBirthday := Self.FBirthday; for LWeekDay := low( TWeekDay ) to high( TWeekDay ) do Dest.SetAvailibility( LWeekDay, Self.GetAvailibility( LWeekDay ) ); end; constructor TEmployee.Create; var LWeekDay: TWeekDay; begin inherited Create; FAvailibility := TObjectDictionary<TWeekDay, TAvailibility>.Create( [ doOwnsValues ] ); for LWeekDay := low( TWeekDay ) to high( TWeekDay ) do begin FAvailibility.Add( LWeekDay, TAvailibility.Create ); end; end; destructor TEmployee.Destroy; begin FAvailibility.Free; inherited; end; function TEmployee.Equals( Obj: TObject ): Boolean; begin Result := ( Self = Obj ) or Assigned( Obj ) and ( Obj is TEmployee ) and ( TEmployee( Obj ).FCardID = Self.FCardID ); end; function TEmployee.GetAvailibility( Weekday: TWeekDay ): TAvailibility; begin Result := FAvailibility[ Weekday ]; end; procedure TEmployee.SetAvailibility( Weekday: TWeekDay; const Value: TAvailibility ); begin FAvailibility[ Weekday ].Assign( Value ); end; procedure TEmployee.SetBirthday( const Value: TDate ); begin FBirthday := DateOf( Value ); end; { TAvailibility } procedure TAvailibility.AssignTo( Dest: TPersistent ); begin if ( Dest is TAvailibility ) then AssignToAvailibility( Dest as TAvailibility ) else inherited; end; procedure TAvailibility.AssignToAvailibility( Dest: TAvailibility ); begin Dest.FFrom := Self.FFrom; Dest.FDuration := Self.FDuration; end; function TAvailibility.Equals( Obj: TObject ): Boolean; begin Result := ( Self = Obj ) or Assigned( Obj ) and ( Obj is TAvailibility ) and ( {} ( TAvailibility( Obj ).FIsAvailable = Self.FIsAvailable ) or {} ( ( TAvailibility( Obj ).FFrom = Self.FFrom ) and ( TAvailibility( Obj ).FDuration = Self.FDuration ) ) ); end; procedure TAvailibility.SetFrom( const Value: TTime ); begin FFrom := TimeOf( Value ); end; procedure TAvailibility.SetIsAvailable( const Value: Boolean ); begin FIsAvailable := Value; end; end. |
AW: Record im Array nutzen? - Sinnvollere Wege?
Also zunächst mal ist zu sagen, dass es in Delphi seit Version 4 bereits dynamische Arrays gibt. Es gibt also keinen Grund, eine Maximalgröße wie „1000“ fest vorzugeben. Feste Größen sind schlecht, weil sie erstens beliebig sind (warum gerade 1000? Was ist, wenn es 1001 Mitarbeiter gibt?) und zweitens, weil sie Platz verschwenden. Schreibe statt
Delphi-Quellcode:
also besser
Employees: array[1..1000] of TEmployee
Delphi-Quellcode:
. Die Größe kannst du mit SetLength zur Laufzeit verändern.
Employees: array of TEmployee
Da es aber mühsam ist, jedes mal beim Hinzufügen eines Elements (vom Löschen fangen wir gar nicht erst an) folgendes zu schreiben
Delphi-Quellcode:
verwendet man besser eine TObjectList oder TList.
SetLength(Employees, length(Employees)+1);
Employees[length(Employees)-1] := NewEmployee; Das mit der festen Höchstlänge gilt auch für Strings. Wenn es nicht wirklich einen guten Grund gibt, dann sollte man nicht
Delphi-Quellcode:
schreiben, sondern einfach
String[100]
Delphi-Quellcode:
.
String
Als Grundproblem sehe ich bei dir die aber die mangelnde Modellierung an. Zunächst mal solltest du die Geschäftslogik strikt von der Darstellung trennen. Du solltest also Termine, Uhrzeiten etc. z.B. intern niemals als String speichern. Statt einen einzelnen Termin ("15:00-17:30") als String zu repräsentieren, der immer wieder geparst werden muss, bastel dir einen speziellen Typen, der genau die Information abbildet:
Delphi-Quellcode:
Dann der nächste Punkt:
TAppointment = record
StartTime: TTime; EndTime: TTime; end; [...] Availability : Array[1..7] of TAppointment;
Delphi-Quellcode:
. Zunächst mal fangen Arrays normalerweise bei 0 an und nicht bei 1. Davon abzuweichen führt eher zu Verwirrungen und Fehlern. Noch wichtiger: Die Zahlen sagen mir nichts über die Bedeutung. Ich kann nur mutmaßen, dass es sich hier um Wochentage handelt. Aber dann ist immer noch die Frage, welche Zahl welchem Tag entspricht. Entspricht die 1 z.B. dem Montag oder dem Sonntag?
Array[1..7]
Besser wäre:
Delphi-Quellcode:
Das sieht schon besser aus.
TWeekday = (wdMonday, wdTuesday, wdWednesday, wdThursday, wdFriday, wdSaturday, wdSunday);
Availability: Array[TWeekday] of TAppointment; Allerdings ist diese Modellierung jetzt natürlich immer noch darauf eingeschränkt, dass es pro Wochentag nur einen Termin gibt. Da kann ich jetzt ohne nähere Informationen zu deinem Anwendungsfall nicht sagen, ob das zu deinem Anwendungsfall passt oder nicht. Aber selbst dann wäre es eventuell besser, einfach eine flache Liste von Terminen zu speichern, die nicht nach Wochentagen gruppiert ist:
Delphi-Quellcode:
So ist man, falls sich die Anforderungen später doch mal ändern, flexibler mit der Art von Terminen, die möglich sind. Man könnte z.B. mehrere Termine an einem Tag haben. Durch hinzufügen eines zusätzlichen Feldes zu TAppointment könnte man sogar unterscheiden zwischen einmaligen Terminen und solchen, die sich jede Woche wiederholen.
TAppointment = record
StartTime: TDateTime; // Beachte: Nun DateTime EndTime: TDateTime; end; [...] Availability: array of TAppointment; // οder bei neueren Delphis Availability: TList<TAppointment>; |
AW: Record im Array nutzen? - Sinnvollere Wege?
Erstmal vielen Dank für die bis jetzt aufgebrachte Mühe!
Ich muss vorab sagen, ich mach das alles nur als Hobby, bin nebenbei noch Schüler und interessiere mich in den Bereich und würde auch gerne in der Richtung studieren wollen und will mir bereits fürs Studium mal schon ein gewisses Basiswissen schaffen. Nun wo fange ich erstmal an. Ich habe mir mal den Programmaufbau von Sir Rufo angeschaut. Ich muss sagen, dass ist für mein Anfängerwissen echt zu hoch. Also da fallen mir viele Fragen ein, wobei ich das mal nur auf das allgemeinste begrenze:
Ich muss sagen, dass dieses Codebeispiel, nochmals danke für diese Mühe extra auf mein Fallbeispiel angepasst eine Unit zu verfassen, für mich eine zu Hohe Hausnummer ist, man vergleiche mal meine Version (Um mal auf Deutsch zu sagen "ein Scheiß dagegen" ist.) Ich habe mich mal desweiteren informiert und muss sagen, dass TObjects sich auf jedenfall besser eignet als meine Method, die wie von euch genannt, zu stark auf die Darstellung ausrichtet ist. Nun zu Namenloser: Bezüglich dem Array, ich gebe dir absolut Recht bezüglich dem Dynamischen Array und würde auch hier lieber TObjectlist nutzen. Also an meinem Anwendungsfall, wird pro Wochentag nur ein Termin genutzt. Denn später werde ich mit der Zeit schauen, ob die betroffene Person an dem Wochentag in einem bestimmten Zeitraum verfügbar ist und dabei wird nur dieser Zeitwert für den einen Wochentag genutzt. Bezüglich 0 und 1 im Array. Ich habe das eig benutzt, damit ich später noch weiß, dass damit von Montag bis Sonntag gemeint ist (7 Tage). Aber die vorgeschlagene Methode ist um einiges besser. Aber ich muss auch später Urlaubstage einfügen, also ich habe mir einfach gedacht, dass ich diese Tage in eine TStringlist reinschreibe und das Programm einfach die Liste durchgeht und wenn der Tag mit dem Tag der Überprüfung übereinstimmt, wird dieser als nicht verfügbar angezeigt. Eine schlussendliche Frage habe ich noch: Als Grundproblem soll meine mangelnde Modellierung schuld sein, kann ich dies irgendwo nachlesen bzw. lernen? Eventuell habt ihr dazu passendes Informationsmaterial zur Hand? Würde gerne daran arbeiten wollen. MfG Asura |
AW: Record im Array nutzen? - Sinnvollere Wege?
Zitat:
Wenn du Objektorientierung verinnerlicht hast, schau dir als nächstes Design Patterns an. |
AW: Record im Array nutzen? - Sinnvollere Wege?
Zur Not kannst du auch erst mal beim Record bleiben, dann mußt du dein Programm nicht komplett neu machen. Records sind aus mehren Gründen allerdings nicht zu empfehlen. Der String[100] kann auch irgendwann mal ein string werden, wenn du satt typisierte Dateien (Annahme) z.B. einen FileStream oder zur Not auch eine MemIniFile verwendest.
Delphi-Quellcode:
TEmployees = class
private function GetCount: integer; procedure SetCount(const Value: integer); public Items: array of TEmployee; property Count: integer read GetCount write SetCount; function Add(const Value: TEmployee): integer; procedure Delete(const Index: integer); procedure Assign(Value: TEmployees); procedure Clear; procedure LoadFromFile(const FileName: string); procedure SaveToFile(const FileName: string); destructor Destroy; override; end; { TEmployees } destructor TEmployees.Destroy; begin Clear; inherited; end; function TEmployees.GetCount: integer; begin Result := Length(Items); end; procedure TEmployees.SetCount(const Value: integer); begin SetLength(Items, Value); end; procedure TEmployees.Clear; begin SetCount(0); end; function TEmployees.Add(const Value: TEmployee): integer; begin Result := Count; SetCount(Result + 1); Items[Result] := Value; end; procedure TEmployees.Delete(const Index: integer); var I: integer; begin for I := Index to Count - 2 do Items[I] := Items[I + 1]; SetCount(Count - 1); end; procedure TEmployees.Assign(Value: TEmployees); var I: integer; begin SetCount(Value.Count); for I := 0 to Count - 1 do Items[I] := Value.Items[I]; end; procedure TEmployees.LoadFromFile(const FileName: string); begin end; procedure TEmployees.SaveToFile(const FileName: string); begin end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:22 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz