0
 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?

JGFMK
  • 8,425
  • 4
  • 58
  • 92

3 Answers3

1

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.

OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
  • Yep - bi-directional references - another way to skin 'that' cat! Again not so great. The nearest design pattern to what I really want I think is a builder - but that's overkill for this as it's just a singleton and an easy initialisation routine with no complexity. – JGFMK Sep 19 '13 at 14:37
0

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.

Johan Sjöberg
  • 47,929
  • 21
  • 130
  • 148
  • I realise this - but an enum is normally based on static content - constants - I need it to be dynamically involved with the command line arguments - per the code I posted – JGFMK Sep 18 '13 at 21:36
  • I'm wondering if I have to revert to the old style private constructor and static final singleton property passing in the args to the constructor that assigns its value. And not use enums in this case... – JGFMK Sep 18 '13 at 21:38
  • 1
    Your use case isn't compatible with enums and involves [reflection](http://stackoverflow.com/questions/3735927/java-instantiating-an-enum-using-reflection). A good warning bell in most situations. – Johan Sjöberg Sep 18 '13 at 21:41
  • 1
    Actually I think singletons aren't supposed to have constructors with arguments so my original code is probably as good as I am going to get. – JGFMK Sep 18 '13 at 22:03
  • @JGFMK singletons may very well have constructor arguments. If you look at the basics of Spring DI, beans are singletons be default. And (although this seems to be some kind of religious debate) there are people which prefer constructor injection over property injection. – skirsch Sep 18 '13 at 22:06
  • Can you elaborate with an adaptation of the code I gave skirsch? – JGFMK Sep 18 '13 at 22:08
  • @JGFMK Well, that could be `new Singleton(args[0], args[1])` which is so obvious that I assume you don't like to hear. I wonder why, though... – skirsch Sep 18 '13 at 22:16
  • @skirsh, no that's incorrect. The **only** way an enum can have a constructor is by the above illustrated approach. And that does **not** allow dynamic parameters. Spring DI provide a shortand to, here, `Singleton.valueOf(str)` - hardly relevant to this discussion. You are indeed correct in enums can well have constructors though - just like I illustrated. – Johan Sjöberg Sep 18 '13 at 22:19
  • @JohanSjöberg Sorry, i did not make myself clear; I was talking about singletons in general, not about enums, as the comments already indicated that enums are not the appropriate approach for this matter. So I wanted to take the discussion to a better solution... – skirsch Sep 18 '13 at 22:22
  • @skirsch, very well. Singleton - the design pattern - won't allow you to have exposed constructor arguments either. A mechanisms such as `Singleton.getInstance().init("foo");` needs to be used. – Johan Sjöberg Sep 18 '13 at 22:27
  • @JohanSjöberg Yeah well, for singleton design patterns that is correct. But if I hear singleton, in my environment that merely means: there's just one instance of a class. And usually it is created and managed by a DI framework or something; and there I can have some constructor arguments. And as it seems that JGFMK wants to have such a kind of a singleton, I was trying to introduce the idea of the DI world and its version of singletons (which are no strict singletons as in the design pattern, yes). – skirsch Sep 18 '13 at 22:46
0

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.

skirsch
  • 1,640
  • 12
  • 24
  • Hi skirsch Thanks for your response. The comment Johan Sjoberg posted about getting into the realms of reflection made me realise - using a DI framework like Spring would be one way to achieve the constructor injection on a singleton - which involves reflection under the covers. I think you end up with a ton of extra boilerplate with this implementation too. The only thing I'd actually change to my original code is to pass the string args array directly into initialise and assign parameters that way - simplifying method signature. – JGFMK Sep 19 '13 at 14:33