Moin,
das hier Vorgestellte versteht sich eher als Konstrukt für eigene Arbeiten.
Aber worum geht es eigentlich? In größeren Projekten ist es ratsam, auf globale Variablen zu verzichten. Wie aber kann man nun globale Informationen zugänglich machen? Man müßte ja die notwendigen Informationen sonst von Methode zu Methode weiterreichen, was doch ziemlich schnell unübersichtliche Methoden-Köpfe zeigt.
Die Lösung ist eine Klasse, die die globalen Daten hält. Ihre Besonderheit besteht darin, daß man stets mit nur einer Instanz arbeitet, und zwar mit der, die man braucht.
Möglich wird dies durch ein Konstrukt, welches ich erstmal komplett darstellen möchte:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60:
| unit UGlobalData;
interface
uses UDataHolder; type TGlobalData = class( TObject ) private _data: TDataHolder; _moreData: String; public class function NewInstance(): TObject; override; procedure FreeInstance; override; end;
implementation
var GGlobalData : TGlobalData = nil; GReferenceCounter: Integer = 0;
class function TGlobalData.NewInstance: TObject; begin if not Assigned( GGlobalData ) then begin GGlobalData := TGlobalData( inherited NewInstance ); GGlobalData._moreData := ''; GGlobalData._data := TDataHolder.Create(); end;
Result := GGlobalData; Inc( GReferenceCounter ); end;
procedure TGlobalData.FreeInstance(); begin Dec( GReferenceCounter ); if GReferenceCounter = 0 then begin GGlobalData := nil;
_data.Free(); inherited FreeInstance; end; end;
end. |
Abgesehen von den privaten Variablen der Klasse (_data, _moreData) und der genutzten Unit (UDataHolder) kann man den Code so übernehmen und anpassen.
Eine Nutzung sieht folgendermaßen aus:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| var globs: TGlobalData; begin globs := TGlobalData.Create(); globs.Free(); end; |
Wo auch immer man in den Sourcen auf TGlobalData zugreifen möchte, greift man auf die Instanz zu, die beim ersten Zugriff angelegt wurde. Möglich wird dies durch GGlobalData, welches direkt unter dem Implementation-Abschnitt deklariert wird. Es ist somit nach außen unsichtbar, was einen Zugriff nur über Create() ermöglicht.
Mit jedem Create wird ein Zähler mitgezählt. Durch ihn erfährt man, wieviele Stellen gerade auf TGlobalData zugreifen. Beim Freigeben der letzten Instanz erst wird das Objekt wirklich freigegeben.
Es gibt aber einiges zu beachten:
1. Man sollte diese Klasse nicht veerbbar machen, weil es ja nur eine Instanz- und Referenz-Variable gibt.
2. Private Variablen der TGlobalData-Klasse (meine Beispiele _data und _moreData) sollten nicht im Konstruktor angelegt werden. Ebensowenig sollten sie im Destruktor freigegeben werden. Hier sollten NewInstance und FreeInstance genutzt werden (, wie die Beispiele auch zeigen).
3. Für Die Arbeit mit Multi-Threading sollte man ein Objekt der Klasse so nutzen, wie andere Variablen, die man zwischen den Threads austauscht.
Ich habe die Klasse im Einsatz und konnte noch keine Fehler feststellen, schließe sie aber nicht aus. Wer welche findet, schreit es heraus.
Viel Spaß damit und gegrüßt!
MitschL
[edit] DanielG und delfiphan wiesen mich auf teilweise schwere Fehler im ersten Code-Listing hin. Vor die Klassendeklaration gehört natürlich ein type und die NewInstance-Methode nutzt in den Zeilen 38/39 nun das richtige Objekt. Dank an beide.