2009-06-26 12 views
114

ich die Singleton Artikel auf Wikipedia zu lesen und ich kam in diesem Beispiel:Singleton mit Argumenten in Java

public class Singleton { 
    // Private constructor prevents instantiation from other classes 
    private Singleton() {} 

    /** 
    * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
    * or the first access to SingletonHolder.INSTANCE, not before. 
    */ 
    private static class SingletonHolder { 
     private static final Singleton INSTANCE = new Singleton(); 
    } 

    public static Singleton getInstance() { 
     return SingletonHolder.INSTANCE; 
    } 
} 

Während ich die Art, wie das wirklich Singleton verhält, kann ich nicht sehen, wie es zur Anpassung an Integriere Argumente in den Konstruktor. Was ist der bevorzugte Weg, dies in Java zu tun? Würde ich so etwas tun müssen?

public class Singleton 
{ 
    private static Singleton singleton = null; 
    private final int x; 

    private Singleton(int x) { 
     this.x = x; 
    } 

    public synchronized static Singleton getInstance(int x) { 
     if(singleton == null) singleton = new Singleton(x); 
     return singleton; 
    } 
} 

Vielen Dank!


Edit: Ich glaube, ich habe einen Sturm der Kontroverse mit meinem Wunsch, Singleton zu verwenden begonnen. Lassen Sie mich meine Motivation erklären und hoffentlich kann jemand eine bessere Idee vorschlagen. Ich verwende ein Grid-Computing-Framework, um Aufgaben parallel auszuführen. Im Allgemeinen habe ich so etwas wie diese:

// AbstractTask implements Serializable 
public class Task extends AbstractTask 
{ 
    private final ReferenceToReallyBigObject object; 

    public Task(ReferenceToReallyBigObject object) 
    { 
     this.object = object; 
    } 

    public void run() 
    { 
     // Do some stuff with the object (which is immutable). 
    } 
} 

Was ist passiert, dass, obwohl ich nur einen Verweis auf meine Daten an alle Aufgaben übergibt, wenn die Aufgaben serialisiert werden, werden die Daten kopiert und über. Ich möchte das Objekt unter allen Aufgaben teilen. Natürlich könnte ich die Klasse ändern, wie so:

// AbstractTask implements Serializable 
public class Task extends AbstractTask 
{ 
    private static ReferenceToReallyBigObject object = null; 

    private final String filePath; 

    public Task(String filePath) 
    { 
     this.filePath = filePath; 
    } 

    public void run() 
    { 
     synchronized(this) 
     { 
      if(object == null) 
      { 
       ObjectReader reader = new ObjectReader(filePath); 
       object = reader.read(); 
      } 
     } 

     // Do some stuff with the object (which is immutable). 
    } 
} 

Wie Sie sehen können, auch hier hat ich das Problem, dass ein anderen Dateipfad vorbei bedeutet nichts, nachdem die erste übergeben wird. Deshalb mag ich die Idee für einen Speicher, der in den Antworten bekannt gegeben wurde. Jedenfalls wollte ich diese Logik in eine Singleton-Klasse abstrahieren, anstatt die Logik zum Laden der Datei in die run-Methode einzufügen. Ich werde kein weiteres Beispiel geben, aber ich hoffe, Sie haben die Idee. Bitte lassen Sie mich Ihre Ideen für einen eleganteren Weg hören, um das zu erreichen, was ich versuche. Danke nochmal!

+1

Das Fabrikmuster ist, was Sie wollen. Im Idealfall sollten Grid-Aufgaben völlig unabhängig von anderen Dingen sein und alle Daten erhalten, die sie zur Ausführung und Rückgabe ihrer Ergebnisse benötigen. Dies ist jedoch nicht immer die praktikabelste Lösung, daher ist die Serialisierung der Daten in eine Datei keine schlechte Idee. Ich denke, das ganze Singleton-Ding ist ein bisschen ein Red-Hering; Du willst kein Singleton. –

+1

Es ist bedauerlich, dass Sie den Begriff Singleton verwendet haben, der mit einem solchen Gepäck kommt. Der richtige Ausdruck für dieses Muster ist eigentlich Interning. Interning ist eine Methode, um sicherzustellen, dass abstrakte Werte nur durch eine Instanz dargestellt werden. String Interning ist die gebräuchlichste Verwendung: en.wikipedia.org/wiki/String_intern_pool. – notnoop

+0

Vielleicht möchten Sie sich Terracotta anschauen.Es verwaltet die Objektidentität im gesamten Cluster. Wenn Sie einen Verweis auf Daten senden, die sich bereits im Cluster befinden, wird er nicht erneut serialisiert. –

Antwort

-4

Singletons werden im Allgemeinen als anti-patterns betrachtet und sollten nicht verwendet werden. Sie machen den Code nicht einfach zu testen.

A Singleton mit einem Argument sowieso keinen Sinn macht - was ist, wenn Sie passieren würde, schrieb:

Singleton s = SingletonHolder.getInstance(1); 
Singleton t = SingletonHolder.getInstance(2); //should probably throw IllegalStateException 

Ihre Singletons auch ist nicht Thread-sicher als mehrere Threads gleichzeitige Anrufe zu getInstance in mehr machen können resultierende als eine Instanz erstellt wird (möglicherweise mit unterschiedlichen Werten von x).

+0

Das ist ziemlich umstritten. – AlbertoPL

+1

Ja, es ist strittig; daher meine Verwendung des Wortes "allgemein". Ich denke, es ist fair zu sagen, dass sie in der Regel als eine schlechte Idee betrachtet werden –

+0

Es ist fraglich - einige Leute behaupten, dass die so genannten "Anti-Muster" passen die Definition von Mustern, es ist nur, dass sie schlechte Muster sind. –

6

Verwenden Sie Getter und Setter, um die Variable festzulegen und den Standardkonstruktor als privat zu definieren. Dann nutzen:

Singleton.getInstance().setX(value); 
+1

Versteh nicht, warum das abgelehnt wurde .. Es ist eine gültige Antwort tbh. :/ – Zack

+0

Ich auch nicht ...? – AlbertoPL

+10

Weil es eine Quatschantwort ist. Stellen Sie sich zum Beispiel ein System vor, bei dem der anfängliche Benutzername und das Passwort für den anfänglichen Admin Konstruktorargumente sind. Nun, wenn ich dies zu einem Singleton mache und tue, was du sagst, bekomme ich Getter und Setter für den Admin, was nicht ganz das ist, was du willst. Obwohl Ihre Option in einigen Fällen gültig sein kann, beantwortet sie nicht wirklich den allgemeinen Fall, der die Frage war. (Ja, ich arbeite an dem System, das ich beschrieben habe und nein, ich würde kein Singleton-Muster verwenden, wenn es nicht die Tatsache wäre, dass die Anweisung "Singleton-Muster hier verwenden" verwendet) – Jasper

2

Der Grund, warum Sie nicht Sinn machen können, wie man zu erreichen, was Sie wahrscheinlich versuchen, zu tun ist, dass das, was Sie versuchen, nicht zu tun, nicht wirklich Sinn machen. Sie möchten getInstance(x) mit verschiedenen Argumenten aufrufen, aber immer das gleiche Objekt zurückgeben? Welches Verhalten wollen Sie, wenn Sie getInstance(2) und dann getInstance(5) anrufen?

Wenn Sie das gleiche Objekt, aber für seinen internen Wert unterschiedlich sein wollen, was nur eine Singleton ist, dann müssen Sie sich überhaupt nicht um den Konstruktor kümmern; Sie geben einfach den Wert getInstance() auf dem Weg des Objekts aus. Natürlich verstehen Sie, dass all Ihre anderen Verweise auf den Singleton nun einen anderen internen Wert haben.Wenn Sie getInstance(2) und getInstance(5) möchten, um verschiedene Objekte zurückzugeben, verwenden Sie andererseits nicht das Singleton-Muster, sondern das Factory-Muster.

35

Ich denke, Sie brauchen etwas wie eine Fabrik, um Objekte mit verschiedenen Parametern instanziiert und wiederverwendet zu haben. Es könnte implementiert werden, indem Sie einen synchronisierten HashMap oder ConcurrentHashMap einen Parameter (ein Integer für ein Beispiel) zu Ihrer 'singleton' parametrisierbaren Klasse zuordnen.

Auch wenn Sie vielleicht an den Punkt kommen, an dem Sie stattdessen reguläre Nicht-Singleton-Klassen verwenden sollten (zum Beispiel benötigen Sie 10.000 unterschiedlich parametrisierte Singleton). Hier

ist ein Beispiel für einen solchen Speicher:

public final class UsefulObjFactory { 

    private static Map<Integer, UsefulObj> store = 
     new HashMap<Integer, UsefulObj>(); 

    public static final class UsefulObj { 
     private UsefulObj(int parameter) { 
      // init 
     } 
     public void someUsefulMethod() { 
      // some useful operation 
     } 
    } 

    public static UsefulObj get(int parameter) { 
     synchronized (store) { 
      UsefulObj result = store.get(parameter); 
      if (result == null) { 
       result = new UsefulObj(parameter); 
       store.put(parameter, result); 
      } 
      return result; 
     } 
    } 
} 

Um es noch weiter zu drücken, die Java enum s können auch (oder als) in Betracht gezogen werden parametrisiert Singletons, obwohl so dass nur eine feste Anzahl statische Varianten.

Wenn Sie jedoch eine verteilte Lösung benötigen, sollten Sie eine laterale Caching-Lösung in Erwägung ziehen. Zum Beispiel: EHCache, Terracotta, etc.

im Sinne der Spanning mehrere VMs auf wahrscheinlich mehrere Computer.

+0

Das würde funktionieren, ausgezeichnete Arbeit . Sehr schlau. :) – Zack

+0

Ja, das ist genau das, was ich brauche. Vielen Dank! Ich stimme zu, dass die Art und Weise, wie ich in meinem Beispiel mit Argumenten umging, nicht viel Sinn ergab, aber ich dachte nicht darüber nach. Siehe meine Erklärung in den Kommentaren von oxbow_lakes 'Antwort. –

+1

Dies ist ** NICHT ** ein Singleton; Sie haben jetzt mehr als eine von ihnen. LOL –

3

In Ihrem Beispiel verwenden Sie kein Singleton. Beachten Sie, dass, wenn Sie die folgenden Aktionen (unter der Annahme, dass die Singleton.getInstance tatsächlich statisch war):

Singleton obj1 = Singleton.getInstance(3); 
Singleton obj2 = Singleton.getInstance(4); 

Dann Werte der obj2.x der 3 ist, nicht 4. Wenn Sie dies tun müssen, ist es eine einfache Klasse machen . Wenn die Anzahl der Werte klein und fest ist, können Sie eine enum verwenden. Wenn Sie Probleme mit der übermäßigen Objekterzeugung haben (was normalerweise nicht der Fall ist), können Sie Werte zwischenspeichern (und Quellen prüfen oder Hilfe holen, da es offensichtlich ist, Caches ohne die Gefahr von Speicherlecks zu erstellen).

Sie könnten auch read this article als Singletons können sehr leicht überstrapaziert werden.

-1

Singleton ist natürlich ein "Anti-Pattern" (Annahme einer Definition eines statischen mit variablem Zustand).

Wenn Sie eine feste Menge von unveränderlichen Wertobjekten möchten, dann sind Aufzählungen der richtige Weg. Für einen großen, möglicherweise offenen Satz von Werten können Sie ein Repository eines Formulars verwenden, das normalerweise auf einer Map Implementierung basiert. Wenn Sie mit Statik zu tun haben, seien Sie vorsichtig mit Threading (entweder ausreichend weit synchronisieren oder verwenden Sie eine ConcurrentMap entweder überprüfen, dass ein anderer Thread Sie nicht geschlagen hat oder verwenden Sie irgendeine Form von Futures).

+3

Nur ein Anti-Pattern, wenn es falsch verwendet wird, obwohl das die Definition eines Anti-Patterns ist. Nur weil du sie dort gesehen hast, wo sie nicht hingehörten, bedeutet das nicht, dass sie keinen Platz haben. – geowa4

+0

Die korrekte Verwendung eines Singleton ist, um inkompetenten Code zu demonstrieren. –

138

Ich werde meinen Punkt sehr deutlich machen: ein Singleton mit Parametern ist kein Singleton.

Ein Singleton ist per Definition ein Objekt, das nicht mehr als einmal instanziiert werden soll. Wenn Sie versuchen, dem Konstruktor Parameter zuzuführen, welchen Sinn hat der Singleton?

Sie haben zwei Möglichkeiten.Wenn Sie Ihre Singleton mit einigen Daten initialisiert werden möchten, können Sie sie mit Daten nach der Instanzierung laden, etwa so:

SingletonObj singleton = SingletonObj.getInstance(); 
singleton.init(paramA, paramB); // init the object with data 

Wenn die Operation Ihre Singleton ausführt wiederkehrend, und mit verschiedenen Parametern jedes Mal, Sie könnte genauso gut die Parameter auf die Hauptmethode ausgeführt wird passieren:

SingletonObj singleton = SingletonObj.getInstance(); 
singleton.doSomething(paramA, paramB); // pass parameters on execution 

In jedem Fall Instanziierung immer parameter weniger sein wird. Sonst ist dein Singleton kein Singleton.

+1

+1 So würde ich es wahrscheinlich beim Codieren machen. In C# würde ich nur Eigenschaften verwenden. Java, wahrscheinlich so. – Zack

+1

Bitte sehen Sie meinen aktualisierten Beitrag. –

+93

Entschuldigung, das stimmt nicht. Es gibt Situationen, in denen Sie dynamisch erstellte Parameter übergeben müssen, die für die Laufzeit der Bohrungsanwendung gleich bleiben. Sie können also keine Konstante innerhalb des Singletons verwenden, sondern müssen diese Konstante übergeben, wenn sie erstellt wird. nachdem es einmal die gleiche Konstante für die Lochzeit passiert hat. Ein Setter macht den Job nicht, wenn Sie diese spezifische Konstante im Konstruktor benötigen. – masi

4

Es gibt eine Diskussion darüber, was ist schlecht und gut über Singletons (mit vielen guten Links) hier - http://c2.com/cgi/wiki?SingletonsAreEvil (Sie den Titel nicht zulassen, täuschen - es ist ziemlich unparteiisch)

I Dependency Injection mit würde vorschlagen zu Steuern Sie die Zusammensetzung Ihrer Anwendung anstelle von strukturellen Mustern wie Fabriken und Singleton.

+1

Yeah Dependency Injection löst alle Probleme von Singletons außer: Testbarkeit, Transparenz, Rückverfolgbarkeit und klare Verträge sein Tween-Anbieter und Verbraucher. – Rob

4

Änderung des Singleton-Musters, das Bill Pugh's initialization on demand holder idiom verwendet. Dies ist ohne den Aufwand von spezialisierten Sprachkonstrukte Thread-sicher (dh flüchtige oder synchronisiert):

public final class RInterfaceHL { 

    /** 
    * Private constructor prevents instantiation from other classes. 
    */ 
    private RInterfaceHL() { } 

    /** 
    * R REPL (read-evaluate-parse loop) handler. 
    */ 
    private static RMainLoopCallbacks rloopHandler = null; 

    /** 
    * SingletonHolder is loaded, and the static initializer executed, 
    * on the first execution of Singleton.getInstance() or the first 
    * access to SingletonHolder.INSTANCE, not before. 
    */ 
    private static final class SingletonHolder { 

     /** 
     * Singleton instance, with static initializer. 
     */ 
     private static final RInterfaceHL INSTANCE = initRInterfaceHL(); 

     /** 
     * Initialize RInterfaceHL singleton instance using rLoopHandler from 
     * outer class. 
     * 
     * @return RInterfaceHL instance 
     */ 
     private static RInterfaceHL initRInterfaceHL() { 
      try { 
       return new RInterfaceHL(rloopHandler); 
      } catch (REngineException e) { 
       // a static initializer cannot throw exceptions 
       // but it can throw an ExceptionInInitializerError 
       throw new ExceptionInInitializerError(e); 
      } 
     } 

     /** 
     * Prevent instantiation. 
     */ 
     private SingletonHolder() { 
     } 

     /** 
     * Get singleton RInterfaceHL. 
     * 
     * @return RInterfaceHL singleton. 
     */ 
     public static RInterfaceHL getInstance() { 
      return SingletonHolder.INSTANCE; 
     } 

    } 

    /** 
    * Return the singleton instance of RInterfaceHL. Only the first call to 
    * this will establish the rloopHandler. 
    * 
    * @param rloopHandler 
    *   R REPL handler supplied by client. 
    * @return RInterfaceHL singleton instance 
    * @throws REngineException 
    *    if REngine cannot be created 
    */ 
    public static RInterfaceHL getInstance(RMainLoopCallbacks rloopHandler) 
      throws REngineException { 
     RInterfaceHL.rloopHandler = rloopHandler; 

     RInterfaceHL instance = null; 

     try { 
      instance = SingletonHolder.getInstance(); 
     } catch (ExceptionInInitializerError e) { 

      // rethrow exception that occurred in the initializer 
      // so our caller can deal with it 
      Throwable exceptionInInit = e.getCause(); 
      throw new REngineException(null, exceptionInInit.getMessage()); 
     } 

     return instance; 
    } 

    /** 
    * org.rosuda.REngine.REngine high level R interface. 
    */ 
    private REngine rosudaEngine = null; 

    /** 
    * Construct new RInterfaceHL. Only ever gets called once by 
    * {@link SingletonHolder.initRInterfaceHL}. 
    * 
    * @param rloopHandler 
    *   R REPL handler supplied by client. 
    * @throws REngineException 
    *    if R cannot be loaded. 
    */ 
    private RInterfaceHL(RMainLoopCallbacks rloopHandler) 
      throws REngineException { 

     // tell Rengine code not to die if it can't 
     // load the JRI native DLLs. This allows 
     // us to catch the UnsatisfiedLinkError 
     // ourselves 
     System.setProperty("jri.ignore.ule", "yes"); 

     rosudaEngine = new JRIEngine(new String[] { "--no-save" }, rloopHandler); 
    } 
} 
+0

Ich denke, es wäre eine gute Idee zu "endlich" RInterfaceHL.rloopHandler = null; } 'in' getInstance', weil diese statische Referenz einen Speicherverlust verursachen kann, wenn wir nicht vorsichtig sind. In Ihrem Fall scheint es kein Problem zu sein, aber ich könnte mir ein Szenario vorstellen, in dem das übergebene Objekt groß ist und nur von 'RInterfaceHL' verwendet wird, um einige Werte zu erhalten und keinen Verweis darauf zu behalten. – TWiStErRob

+0

Idee: 'return SingletonHolder.INSTANCE' würde in' getInstance' genauso gut funktionieren. Ich denke nicht, dass hier eine Verkapselung notwendig ist, da die äußere Klasse die Innereien der inneren Klasse bereits kennt, sie sind eng miteinander verbunden: Sie weiß, dass "rloopHandler" init benötigt, bevor sie anruft. Auch der private Konstruktor hat keine Wirkung, da die privaten Sachen der inneren Klasse für die äußere Klasse einfach verfügbar sind. – TWiStErRob

3

Ein weiterer Grund Singletons ein Anti-Muster sind, ist, dass geschrieben, wenn nach Empfehlungen, mit privaten Konstruktor, sie sind sehr schwer zu Unterklasse und konfigurieren, um in bestimmten Komponententests zu verwenden. Wird zum Beispiel benötigt, um Legacy-Code zu verwalten.

8

Sie können auch das Builder-Muster verwenden, wenn Sie zeigen möchten, dass einige Parameter obligatorisch sind.

public enum EnumSingleton { 

    INSTANCE; 

    private String name; // Mandatory 
    private Double age = null; // Not Mandatory 

    private void build(SingletonBuilder builder) { 
     this.name = builder.name; 
     this.age = builder.age; 
    } 

    // Static getter 
    public static EnumSingleton getSingleton() { 
     return INSTANCE; 
    } 

    public void print() { 
     System.out.println("Name "+name + ", age: "+age); 
    } 


    public static class SingletonBuilder { 

     private final String name; // Mandatory 
     private Double age = null; // Not Mandatory 

     private SingletonBuilder(){ 
      name = null; 
     } 

     SingletonBuilder(String name) { 
      this.name = name; 
     } 

     public SingletonBuilder age(double age) { 
      this.age = age; 
      return this; 
     } 

     public void build(){ 
      EnumSingleton.INSTANCE.build(this); 
     } 

    } 


} 

Dann könnten Sie erstellen/instantiate/parametrisiert es wie folgt:

public static void main(String[] args) { 
    new EnumSingleton.SingletonBuilder("nico").age(41).build(); 
    EnumSingleton.getSingleton().print(); 
} 
0

Dies ist kein ganz Singleton, sondern kann etwas sein, das Ihr Problem beheben könnte.

public class KamilManager { 

    private static KamilManager sharedInstance; 

    /** 
    * This method cannot be called before calling KamilManager constructor or else 
    * it will bomb out. 
    * @return 
    */ 
    public static KamilManager getInstanceAfterInitialized() { 
    if(sharedInstance == null) 
     throw new RuntimeException("You must instantiate KamilManager once, before calling this method"); 

    return sharedInstance; 
} 

    public KamilManager(Context context, KamilConfig KamilConfig) { 
    //Set whatever you need to set here then call: 
    s haredInstance = this; 
    } 
} 
1

Wenn wir das Problem als nehmen „wie Singleton zu machen mit Zustand“ ist, dann ist es nicht notwendig, den Zustand als Konstruktor Parameter zu übergeben. Ich stimme den Posts zu, die die Zustände initialisieren oder nach dem Abrufen der Singleton-Instanz die set-Methode verwenden.

Eine andere Frage ist: Ist es gut, Singleton mit Zustand zu haben?

5

Überrascht, dass niemand erwähnt, wie ein Logger erstellt/abgerufen wird. Zum Beispiel zeigt unten, wie Log4J logger abgerufen wird.

// Retrieve a logger named according to the value of the name parameter. If the named logger already exists, then the existing instance will be returned. Otherwise, a new instance is created. 
public static Logger getLogger(String name) 

Es gibt einige Stufen von Umwegen, aber der Schlüssel Teil unter method, die so ziemlich alles erzählt, wie es funktioniert. Es verwendet eine Hash-Tabelle, um die ausgehenden Logger zu speichern, und der Schlüssel wird aus dem Namen abgeleitet. Wenn der Logger für einen angegebenen Namen nicht existiert, verwendet er eine Factory, um den Logger zu erstellen, und fügt ihn dann zur Hash-Tabelle hinzu.

69 Hashtable ht; 
... 
258 public 
259 Logger getLogger(String name, LoggerFactory factory) { 
260 //System.out.println("getInstance("+name+") called."); 
261 CategoryKey key = new CategoryKey(name); 
262 // Synchronize to prevent write conflicts. Read conflicts (in 
263 // getChainedLevel method) are possible only if variable 
264 // assignments are non-atomic. 
265 Logger logger; 
266 
267 synchronized(ht) { 
268  Object o = ht.get(key); 
269  if(o == null) { 
270  logger = factory.makeNewLoggerInstance(name); 
271  logger.setHierarchy(this); 
272  ht.put(key, logger); 
273  updateParents(logger); 
274  return logger; 
275  } else if(o instanceof Logger) { 
276  return (Logger) o; 
277  } 
... 
1

Könnten wir nicht etwas tun:

public class Singleton { 

    private int x; 

    // Private constructor prevents instantiation from other classes 
    private Singleton() {} 

    /** 
    * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
    * or the first access to SingletonHolder.INSTANCE, not before. 
    */ 
    private static class SingletonHolder { 
     private static final Singleton INSTANCE = new Singleton(); 
    } 

    public static Singleton getInstance(int x) { 
     Singleton instance = SingletonHolder.INSTANCE; 
     instance.x = x; 
     return instance; 
    } 
} 
2

"A Singleton mit Parametern ist kein Singleton" Aussage ist nicht ganz korrekt. Wir müssen dies aus der Perspektive der Anwendung und nicht aus der Perspektive des Codes analysieren.

Wir erstellen Singleton-Klasse, um eine einzelne Instanz eines Objekts in einem Anwendungslauf zu erstellen. Wenn Sie einen Konstruktor mit Parameter verwenden, können Sie Flexibilität in Ihren Code einbauen, um bei jeder Ausführung Ihrer Anwendung einige Attribute Ihres Singleton-Objekts zu ändern. Dies ist keine Verletzung des Singleton-Musters. Es sieht aus wie eine Verletzung, wenn Sie dies aus der Code-Perspektive sehen.

Design Patterns helfen uns, flexiblen und erweiterbaren Code zu schreiben, der uns nicht daran hindert, guten Code zu schreiben.

+7

Dies ist keine Antwort auf die OP-Frage, dies sollte ein Kommentar sein. –

3

Sie können eine Initialisierungsmethode hinzufügen, um Instanziierung von Holen zu trennen.

public class Singleton { 
    private static Singleton singleton = null; 
    private final int x; 

    private Singleton(int x) { 
     this.x = x; 
    } 

    public static Singleton getInstance() { 
     if(singleton == null) { 
      throw new AssertionError("You have to call init first"); 
     } 

     return singleton; 
    } 

    public synchronized static Singleton init(int x) { 
     if (singleton != null) 
     { 
      // in my opinion this is optional, but for the purists it ensures 
      // that you only ever get the same instance when you call getInstance 
      throw new AssertionError("You already initialized me"); 
     } 

     singleton = new Singleton(x); 
     return singleton; 
    } 

} 

Dann rufen Sie Singleton.init(123) einmal von irgendwo zu konfigurieren, in der App Startup zum Beispiel.

0

Trotz allem, was einige behaupten kann, ist hier ein Singleton mit Parametern in Konstruktor

public class Singleton { 

    private static String aParameterStored; 

    private static final Singleton instance = new Singleton("Param to set"); 

    private Singleton() { 
     // do nothing 
    } 

    private Singleton(String param) { 
     aParameterStored = param; 
    } 

    public static Singleton getInstance() { 
     return instance; 
    } 

    /* 
    * ... stuff you would like the singleton do 
    */ 
} 

Das Singletonmuster sagen:

  • sicherzustellen, dass nur eine Instanz der Singleton-Klasse jemals
  • existiert
  • globalen Zugriff auf diese Instanz bereitstellen.

die in diesem Beispiel berücksichtigt werden.

Warum nicht direkt die Eigenschaft festlegen? Es ist Lehrbuch Fall zu zeigen, wie wir einen Singleton mit Konstruktor mit Parameter bekommen können, aber es könnte in einigen Situationen nützlich sein. Zum Beispiel in Vererbungsfällen, um das Singleton zu zwingen, einige Superklasseneigenschaften zu setzen.

1

Wenn Sie eine Singleton-Klasse erstellen möchten, die als Kontext dient, können Sie eine Konfigurationsdatei verwenden und die Parameter aus der Datei instance() lesen.

Wenn die Parameter, die die Singleton-Klasse speisen, während der Ausführung Ihres Programms dynamisch abgerufen werden, verwenden Sie einfach eine statische HashMap, die verschiedene Instanzen in Ihrer Singleton-Klasse speichert, um sicherzustellen, dass für jeden Parameter nur eine Instanz erstellt wird.