Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Delphi Singleton, Instanz ohne Instanziierung?
Stephan.Woebbeking - Mo 15.04.13 08:45
Titel: Delphi Singleton, Instanz ohne Instanziierung?
Hallo, ich habe eine Frage und bin grad ziemlich verwirrt, weil das Verhalten der IDE so gar nicht zu meinem Verständnis passt. Eines von beidem muss also korrigiert werden. ;)
Ich habe den folgenden Code:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| procedure TFormMain.MnuShowLicensesClick(Sender: TObject); var grant: Boolean; store1, store2: TLicenseStore; begin if ( Sender = MnuGrantLicenses ) then begin grant := True; store1 := TLicenseStore.Create( LICENSE_PW ); store2 := TLicenseStore.Create( LICENSE_PW ); FormLicenseStore.store := TLicenseStore.Create( LICENSE_PW ); end else begin grant := False; FormLicenseStore.store := TLicenseStore.Instance; end; FormLicenseStore.allowGrant := grant; FormLicenseStore.allowFileOp := grant; FormLicenseStore.ShowModal; if ( grant ) then FormLicenseStore.store.Free; end; |
Die Variablen store1 und store2 sind nur zum spielen hinzugefügt. Die Idee ist, dass TLicenseStore über eine Singleton Implementierung eine Instanz zur Verfügung stellt. Quasi die Instanz mit der ich "im Allgemeinen" in der Applikation arbeite. Allerdings brauche ich - eben in dieser Funktion - doch mal für eine begrenzte Zeit eine unabhängige Instanz. Die erzeuge ich lokal, nutze sie und werf sie dann wieder weg - siehe Code. Soweit auch alles einfach und gut (theoretisch).
Jetzt komme ich während der Laufzeit aber zu dem angehängten Bild. Dort erkennt man, dass der allgemeine Sourceteil (grant=False) durchlaufen wird. Und obwohl die Instanziierung von store1 nie durchlaufen wurde (Nur dieser eine Aufruf der Funktion nach Programmstart!), zeigt store1 auf gültige Werte. Und auch noch auf die meiner im TLicenseStore gespeicherten Instanz... ???? Jemand eine Idee?
Noch schlimmer: wenn ich den anderen Teil der Funktion nutze, arbeitet store1 immer noch mit der Singleton und löscht diese Systemweite am Ende - nicht etwa die temporäre Instanz??? Grauenhaft und ich hab derzeit keinen blassen Schimmer?
Achja, hier noch ein Auszug aus TLicenseStore:
Delphi-Quelltext
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:
| TLicenseStore = class private class var pLicStore: TLicenseStore; licenses: array of TLicenseFile; password: String; zipMaster: TZipMaster19; function GetCount: Integer; function GetLicense( idx: Integer ): TLicenseFile; procedure AddLicense( lic: TLicenseFile ); public class function Instance( password: String ) : TLicenseStore; overload; class function Instance : TLicenseStore; overload;
constructor Create( password: String ); destructor Destroy; override; procedure Clear; procedure LoadLicenseFiles( folder: String ); procedure SaveLicenseFiles( folder: String ); function CheckPassword( password: String ): Boolean; procedure SaveLicenseFile( folder: String; idx: Integer ); function CreateRequest( serial, customer1, customer2, computerSpecification: String; deviceType: TDeviceType ): Integer; function FindSerial( serial: String ): Integer; function CheckAccess( serial: String; deviceType: TDeviceType ): Boolean; overload; function CheckAccess( serial: String; deviceType: TDeviceType; customer1: String ): Boolean; overload; procedure GrantLicense( serial: String; licType: TLicType; retirement: TDateTime; transferable: Boolean ); procedure GrantUnlimitedLicense( serial: String; transferable: Boolean ); procedure GrantUnlimitedTransferableLicense( serial: String ); property LicenseFile[ idx: Integer ]: TLicenseFile read GetLicense; default; property Count: Integer read GetCount; procedure Sort( column: TLicSort ); end; |
Danke,
Stephan
Add: Übrigens zeigt auch store2 auf EXAKT dieselbe Instanz soweit ich das erkennen kann...?
Add: Umbenennen der "Instance" Methoden bringt nichts.
Add: Aber: Wenn ich die pLicStore nicht als Klassenvariable sondern als globale Variable definiere, dann geht es???
Blup - Di 16.04.13 08:38
TLicenseStore darf kein Singelton sein, da in deiner Anwendung mehrere Instanzen benötigt werden.
Deshalb würde ich da nur die fachliche Logik implementieren.
Davon könnte man eine Klasse z.B. TGlobalLicenseStore ableiten, die zusätzlich die Funktionalität eines Singelton bereitstellt.
Diese merkt sich intern ob bereits eine Instanz erstellt wurde und gibt diese bei erneutem Aufruf des Konstruktors zurück.
Stephan.Woebbeking - Di 16.04.13 09:04
Hi, danke für die Antwort,
ich verstehe allerdings noch immer nicht, wo das Problem entsteht. Mehrere Instanzen ok, dann lass uns das nicht mehr Singleton nennen, weil es ja kein "echtes" ist, das ist mir schon klar. Aber was spricht dagegen, eine "allgemeine" Instanz als Klassenvariable zu halten und trotzdem temporär "individuelle" Instanzen zuzulassen? Warum manipulieren diese individuellen Instanzen immer auch die allgemeine, das ist doch die Kernfrage?
Stephan
Blup - Di 16.04.13 09:41
Die Antwort ist recht einfach:
Die Klasse ist so implementiert, daß der Konstruktor nur beim ersten Aufruf eine Instanz erzeugt.
Bei jedem weiteren Aufruf wird nur die intern gespeicherte Instanz zurückgegeben.
Wenn ein andere Verhalten gewünscht wird, könnte man z.B. einen weiteren Konstruktor einführen, der jedes mal eine neue Instanz liefert, ohne die Klassenvariable zu beeinflussen.
Ich halte diesen Weg aber für ungünstiger.
Martok - Di 16.04.13 14:29
Blup hat folgendes geschrieben : |
Die Klasse ist so implementiert, daß der Konstruktor nur beim ersten Aufruf eine Instanz erzeugt.
Bei jedem weiteren Aufruf wird nur die intern gespeicherte Instanz zurückgegeben. |
Eben gerade andersrum... Instance() gibt das Singleton zurück, Create() erstellt eine neue (würde ich aus dem geposteten Code vermuten).
Und das sollte so funktionieren, eigentlich. Bin mir mit class var allerdings nicht sicher, wie die genau funktionieren (also wessen private das ist). Ist das auch so, wenn du ein wirklich minimales Testprogramm baust?
Stephan.Woebbeking - Mi 17.04.13 10:08
Hallo Martok, du hast es ziemlich gut erfasst... Ich sehe dort auch nirgendwo ein Problem, aber tatsächlich bekomme ich den Fehler in einer Rekonstruktion nicht hin. Vielleicht liegt der Fehler ganz wo anders; obwohl ich nicht den geringsten Ansatz sehe, wo das sein könnte...
Ich probier noch mit der Rekonstruktion, aber dort klappt alles so, wie es soll...
Stephan
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!