4 Stimmen

Wie kann ich auf meine Singletons zugreifen, ohne den globalen Status zu verwenden?

Ich weiß, dass das Singleton-Muster schlecht ist, weil es einen globalen Zustand verwendet. Aber in den meisten Anwendungen braucht man eine einzige Instanz einer Klasse, wie eine Datenbankverbindung. Also habe ich mein Datenbankobjekt ohne das Singleton-Muster entworfen, aber ich instanziere es nur einmal.

Meine Frage ist, wie kann ich mein Objekt in den Low-Level-Klassen (tief im Objektgraphen) zugreifen, ohne es überall zu übergeben?

Nehmen wir an, ich habe einen Anwendungscontroller, der einen Seitencontroller instanziiert, der ein Benutzermodell instanziiert, für das das Datenbankobjekt erforderlich ist (fragen Sie eine Fabrik, um es zu instanziieren).

Weder mein App-Controller noch mein Page-Controller müssen etwas über das Datenbankobjekt wissen, aber die User-Klasse schon. Wie soll ich das Objekt an sie übergeben?

Vielen Dank für Ihre Zeit!

4voto

Artefacto Punkte 93200

Erwägen Sie die Verwendung eines globalen Containers:

  • Sie registrieren die Objekte, die für die verschiedenen Teilsysteme der Anwendung tatsächlich relevant sind.
  • Sie beantragen dann, dass der Container diese Objekte enthält.

Dieser Ansatz ist in Dependency Injection Frameworks sehr beliebt (siehe Symfony DI, Yadif).

2voto

Mark Seemann Punkte 216836

Singleton ist schlecht, daran besteht kein Zweifel.

In dem von Ihnen beschriebenen Fall ist das Datenbankobjekt ein Umsetzungsdetails des Benutzerobjekts. Die darüber liegenden Schichten brauchen nur den Benutzer zu kennen, nicht das Datenbankobjekt.

Dies wird noch viel deutlicher, wenn Sie das Benutzerobjekt hinter einer Schnittstelle verstecken und nur diese Schnittstelle von den darüber liegenden Schichten konsumieren.

Der Page Controller sollte sich also nur mit der Schnittstelle befassen, nicht mit der konkreten Klasse, die vom Datenbankobjekt abhängt, aber wie erzeugt er neue Instanzen? Er verwendet eine injizierte Abstrakte Fabrik um Instanzen der Schnittstelle zu erstellen. Sie kann mit jeder Implementierung dieser Schnittstelle umgehen, nicht nur mit derjenigen, die auf einem Datenbankobjekt beruht.

Auch hier verstecken Sie den Page Controller hinter einer Schnittstelle. Das bedeutet, dass die Abhängigkeit der konkreten Implementierung von der abstrakten Fabrik zu einem weiteren Implementierungsdetail wird. Der Application Controller konsumiert nur die Schnittstelle des Page Controllers.

Sie können Objekte auf diese Weise umhüllen, ohne jemals Instanzen weitergeben zu müssen. Nur in der Zusammensetzung Wurzel müssen Sie alle Abhängigkeiten miteinander verbinden.

Siehe hier für eine verwandte Antwort mit Beispielen in C#: Ist es besser, ein Singleton für den Zugriff auf den Unity-Container zu erstellen oder ihn durch die Anwendung zu leiten?

0voto

Chris Henry Punkte 11720

Die Art und Weise, wie ich dies immer erreicht habe, ist die Implementierung einer statischen getInstance Funktion, die einen Verweis auf die einzelne Instanz dieser Klasse zurückgibt. Solange Sie sicherstellen, dass der einzige Weg, auf das Objekt zuzugreifen, über diese Methode führt, können Sie sicherstellen, dass Sie nur eine Instanz des Singletons haben. Zum Beispiel:

Klasse deeply_nested_class {

public function some_function() {

$singleton = Singleton::getInstance();

}

}

0voto

WW. Punkte 22847

Beim Laden/Speichern eines Benutzers über die Datenbank gibt es zwei Hauptobjekte: den Benutzer und das Repository.

Sie scheinen die Funktionalität auf der Benutzerseite implementiert zu haben, aber ich denke, sie gehört in das Repository. Sie sollten den Benutzer an das Repository übergeben, um ihn zu speichern.

Aber wie kommt man an das Repository heran? Es wird einmal auf der obersten Ebene erstellt und an die Dienste weitergegeben, die es benötigen.

Das Diagramm der Konstruktionsabhängigkeit und das Diagramm der Aufrufabhängigkeit sind nicht dasselbe.

0voto

Sam Holder Punkte 31723

Bei dem von Ihnen geschilderten Beispiel sind Sie fast am Ziel. Sie verwenden bereits eine Fabrik, um Ihren Seitencontroller zu instanziieren, aber Ihr Seitencontroller instanziiert die Benutzer direkt und da Ihr Benutzer die Datenbank kennen muss.

Sie möchten eine Fabrik verwenden, um Ihre Benutzerobjekte zu instanziieren. Auf diese Weise kann die Fabrik über die Datenbank Bescheid wissen und User-Instanzen erstellen, die ebenfalls über die Datenbank Bescheid wissen. Sie sind wahrscheinlich besser dran, wenn Sie Schnittstellen für alle Abhängigkeiten erstellen, was beim Testen hilft und bedeutet, dass Ihr Code gut entkoppelt ist.

Erstellen Sie eine IUserFactory, die IUser-Implementierungen erstellt, und übergeben Sie diese an Ihre PageControllerFactory, dann muss Ihr ApplicationController nur von der PageControllerFactory wissen, er braucht nichts über die IUserFactory oder die Datenbank zu wissen.

Dann können Sie beim Starten Ihrer Anwendung alle Abhängigkeiten erstellen und sie über die Konstruktoren ineinander injizieren.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X