Ich habe eine Frage zu Singletons, von denen ich denke, dass ich die Antwort kenne ... aber jedes Mal, wenn das Szenario auftaucht, achte ich mich ein wenig selbst, damit ich die konkrete Antwort wissen möchte.
Sagen wir, ich habe zwei Klassen als so eingerichtet ...
%Vor%Meine Frage ist einfach.
Ich frage mich, ob das _classB-Feld auch als statisch behandelt wird, wenn ich auf den Singleton für ClassA zugreife? Obwohl ich _classB nicht als statisches Mitglied deklariert habe.
Ich habe immer im Grunde nur erraten, dass _classB es als statisch (ein Speicherort) behandelt wird, aber ich würde gerne sicher wissen. Liege ich falsch? Wird jedes Mal ein neues Objekt für _classB erstellt, wenn Sie von Singleton ClassA darauf zugreifen ... obwohl nur ein ClassA im Speicher vorhanden ist? Oder liegt es daran, dass ich _classB bei der Deklaration, die bewirkt, dass es nur eine Instanz gibt, neu erstellt habe?
Vielen Dank im Voraus, -Matt
Wenn Sie einen Singleton erstellen, erstellen Sie eine einzelne statische Instanz eines nicht statischen Typs.
In diesem Fall enthält Ihr Typ (Klasse A) einen Verweis auf einen anderen Typ (Klasse B). Die statische Instanz enthält einen einzelnen Verweis auf eine einzelne Instanz eines Klasse-B-Objekts. Technisch gesehen ist es nicht "statisch", aber da es zu einem statischen Objekt (der Instanz der Klasse A) verwurzelt ist, verhält es sich wie eine statische Variable. Sie haben immer ein und nur ein Klasse-B-Objekt (auf das von Ihrer Klasse-A-Instanz verwiesen wird). Sie werden nie mehr als eine Klasse B-Instanz innerhalb der Klasse A erstellen.
Es besteht jedoch keine Gefahr, dass eine zweite Instanz der Klasse B an anderer Stelle erzeugt wird - dies wäre eine andere Instanz.
_classB ist ein Instanzenelement (nicht statisch) von ClassA. Jede Instanz von ClassA hat eine Instanz von _classB (angesichts des Feldinitialisierers, den Sie geschrieben haben). Wenn Sie also das Singleton-Muster verwenden, um auf ClassA zuzugreifen, und somit immer (höchstens) eine Instanz von ClassA geladen haben, haben Sie immer (höchstens) eine Instanz von ClassB über ClassA geladen.
Da ClassB jetzt einen öffentlichen Standardkonstruktor hat, kann etwas anderes in der Ferne Instanzen selbst erstellen. Wenn dies ein Problem ist, sollten Sie die ClassB-Klasse als privat betrachten. Da ClassA über einen öffentlichen Standardkonstruktor verfügt, verhindert auch nichts, dass Benutzer beliebig viele Instanzen erstellen können. Sie könnten den Konstruktor no-arg als privat setzen:
%Vor% Das Singleton-Muster stellt sicher, dass immer nur eine Instanz von ClassB
von der Singleton-Instanz von ClassA
aus auf zugreifbar ist. Der springende Punkt des Singleton-Patterns ist, dass es garantiert, dass nur eine Instanz von ClassA
jederzeit verfügbar ist, also nur eine Referenz auf _classB
(obwohl da ClassA
veränderbar ist, diese Referenz kann ändern).
Beachten Sie jedoch, dass der Bereich von ClassB
immer noch auf Instanzebene und nicht auf statischer Ebene ist. Der Compiler wird nie etwas so seltsames tun, um einen anderen Bereichsspezifizierer zu verwenden, als Sie angeben. Sie müssen immer noch auf den Verweis auf ClassB
über eine Instanz zugreifen, unabhängig davon, ob Sie ein Singleton verwenden oder nicht.
Indem Sie Ihre Erklärung wie folgt haben:
%Vor%Sie implementieren _classB immer dann in eine neue Instanz von ClassB, wenn der Konstruktor von ClassA aufgerufen wird.
Bei einem Singleton-Muster ist der einzige Aufruf des Konstruktors von ClassA die Verwendung einer statischen Methode (in Ihrem Fall durch die Instance-Eigenschaft), wodurch sichergestellt wird, dass nur ein ClassA erstellt wird.
Dies stellt sicher, dass _classB nur einmal aktualisiert wird, aber es ist nicht statisch. Wenn jedoch jemand in der Zukunft ClassA geändert hat, um kein Singleton mehr zu sein, würden Sie mehrere Instanzen von ClassB erstellen. Wenn _classB wirklich statisch wäre, wäre das nicht der Fall.
Wie definiert, verletzt ClassA die Definition für Singleton. Stellen Sie sich vor, dass zwei Threads gleichzeitig die statische Instance-Eigenschaft aufrufen. Da der Zugriff nicht synchronisiert ist, könnten Sie mit zwei verschiedenen Instanzen von ClassA und damit zwei verschiedenen Instanzen von ClassB kommen.
Markieren Sie ClassB einfach als statisch, wenn Sie nur eine Instanz haben möchten.
Meiner Meinung nach ist es immer besser, klaren Code zu schreiben, der Ihnen die vollen Absichten zeigt. Auf diese Weise muss die nächste Person, die an Ihrem Code arbeitet, kein Ratespiel spielen, um zu bestimmen, was Sie tun möchten.
Da ClassA ein Singleton ist, gibt es in Ihrer Anwendung nur eine Instanz davon. Innerhalb dieser Klasseninstanz gibt es ein Member zum Speichern einer ClassB-Variablen. Sobald Sie diese Variable initialisiert haben, handelt es sich um eine Instanzvariable. Da Sie jedoch nur eine Instanz von ClassA haben, erhalten Sie immer dieselbe Instanz von ClassB.
Ich würde auch empfehlen, die interne Instanz nicht zu erstellen, da sie nicht threadsicher ist.
%Vor%durch nicht faulen Laden, und sofort initialisieren, stellen Sie Threadsicherheit sicher.
_classB ist nicht statisch; Eine Instanz von ClassA enthält einen Verweis auf eine Instanz von _classB; Wenn die Instanz von ClassA statisch ist (wie in der Singleton-Instanz), enthält sie immer noch einen Verweis auf _classB, aber neue Instanzen von ClassA enthalten DIFFERENT-Verweise auf (möglicherweise) verschiedene Instanzen von _classB. Wenn Sie also über das Singleton-Muster auf dieselbe Instanz von ClassA verweisen, erhalten Sie immer noch dieselbe Instanz von _classB; Wenn Sie jedoch eine neue Instanz von ClassA erstellen, erhalten Sie eine andere Instanz von _classB, weshalb _classB nicht statisch ist.
Ich bin überrascht, dass niemand darauf hingewiesen hat, dass ClassB
eine öffentliche Eigenschaft von ClassA
bei einem öffentlichen Setter ist. Nichts hält jemanden davon ab etwas zu schreiben wie:
Dies würde die Instanz von ClassB
löschen, die zum Zeitpunkt der Erstellung der Einzelinstanz von ClassA
erstellt wurde, und würde sie durch die neu erstellte Instanz von ClassB
ersetzen.
Ein verwandtes Szenario ist, dass solange _classB
in einer abgeleiteten Klasse gesetzt werden kann (zB wenn der Setter für ClassB
geschützt wurde), kann nicht garantiert werden, dass es nur eine einzige Instanz von% geben würde. co_de% immer.
Ich denke, der richtige Weg, um diese Art von Code zu schreiben, wäre, sowohl ClassB
und ClassA
als Singletons zu implementieren und ClassB
zu einer inneren Klasse von ClassB
zu machen (sonst hätten Sie 2 nicht zusammenhängende Klassen ClassA
und ClassA
mit einem Verweis auf ClassB
verfügbar durch ClassB
, was (in diesem Szenario) nicht von ClassA.Instance.ClassB
abweichen würde.
Wenn ClassB.Instance
nur innerhalb von ClassB
instanziierbar ist, könnte es möglicherweise andere Instanzen von ClassA
instanziierbar in einer abgeleiteten Klasse geben.
Tags und Links c# design-patterns singleton static