JGFMK
JGFMK

Reputation: 8904

Is it possible to have a Java singleton using an enum that uses constructor arguments

 public enum Singleton  {
            INSTANCE;
            String fromLocation;
            String toLocation;

            private void initialise(String fromLocation, String toLocation) {
                this.fromLocation = fromLocation;
                this.toLocation = toLocation;
            }

            public static void main(String[] args) {
                Singleton s = INSTANCE;
                s.initialise(args[0],args[1]);
            }
    }

I can't seem to fathom the syntax to have a normal Java class constructor that I can pass args too from the main routine. The initialise routine to me seems a bad smell - but it's the best I've been able to come up with. Any suggestions?

Upvotes: 0

Views: 2351

Answers (3)

skirsch
skirsch

Reputation: 1747

You're probably mean something like this:

public class Singleton {
  private static Singleton instance;
  public static void getInstance() {
    if (instance == null)
      throw new IllegalStateException("Singleton not initialized!");
    return instance;
  }
  public static void init(String from, String to) {
    if (instance != null)
      throw new IllegalStateException("Singleton already initialized!");
    instance = new Singleton(from, to);
  }
  private final String from;
  private final String to;
  private Singleton(String from, String to) {
    this.from = from;
    this.to = to;
  }
}

Obviously, this is not thread-safe etc. But to be honest, you're better off using a dependecy injection framework like Spring or Guice. This Singleton.getInstance() calls in your code are not what you want to have in the long run...

Why not use/define an enum? It says "An enum type is a special data type that enables for a variable to be a set of predefined constants." in the Java tutorial. And you are obviously not dealing with some constants.

Upvotes: 0

OldCurmudgeon
OldCurmudgeon

Reputation: 65851

The problem with your approach stems from the primary reason enums are so good as singletons.

Let me suggest an analogy with Schrödinger's cat thought experiment. An enum is like the state of the cat, it is instantly completely known when the box is opened and stays that way forever. This is guaranteed by the nature of an enum, i.e. however many people look in the box it is only the first viewer of the state of the cat that actually causes the cat to have a state. Everyone else sees an exact copy of that moment.

You therefore have two ways to install outside data into the final state of the enum. You can either guarantee to be the one that opens the box first or - and here I stretch the analogy a little - you teach the cat to quickly reach out and grab it's state when the box first opens.

Option 1 is as complex as achieving the singleton. Being absolutely sure you are first is well nigh impossible.

So option 2 could look something like:

public enum Singleton {

  INSTANCE;
  final String fromLocation;
  final String toLocation;

  private Singleton () {
    // Reach out.
    this.fromLocation = App.args[0];
    this.toLocation = App.args[1];
  }
}

and your App entry point looks like:

class App {
  static String[] args;

  public static void main(String args[]) {
    App.args = args;
  }
}

There are dire warnings here. Firstly, every app that uses your singleton will break if you do not start it at App.main. Secondly, if you access your singleton anywhere in your App class, it will probably break.

Upvotes: 1

Johan Sjöberg
Johan Sjöberg

Reputation: 49197

No, the way enum constructors work is by

public enum Singleton {
     A("from", "too"),
     B("from2", "too2");

     private String from, to;

     private Singleton(String from, String too) {
         this.from = from;
         this.too = too;
     }
}

What are you really trying to achieve? Perhaps an enum isn't what you're looking for, especially if you look to assign it values runtime.

Upvotes: 0

Related Questions