This week's giveaway is in the Java/Jakarta EE forum. We're giving away four copies of Java EE 8 High Performance and have Romain Manni-Bucau on-line! See Kai [ October 31, 2006: Message edited by: Kai Witte ]
The code shown in case 1 above isn't a singleton at all, and has several other problems. It needs a private constructor, the getInstance() method would need to be static in order to be useful, and the validateDate() method should be nonstatic in order for there to be any point at all to getting an instance.
Singletons tend to be massively overused anyway. Often it's not really that important that there be only one instace of the class, but there's also no particular reason to need more than one. So attempting to limit the number of instances created is a nice idea, but may not be that important. Don't assume it's a vital requirement that there be only one instance, because in reality it's very difficult (impossible really) to ensure in all cases. (Unless you're certain for some reason that no other classloaders will load the class in question.) So if you don't really need this as a requirement, dont assume it's a requirement just because you see a lot of discussion about singletons and ensuring there's only one instance.
Going back to other parts of the original question though - why use nonstatic methods and force the user to create an instance? Initially it seems to give us additional complexity without apparent benefit. But I believe there are often benefits to this approach, even though they aren't immediately apparent. Not that you usually can't eliminate all static methods anyway - e.g., the getInstance() method above needs to be static to be of any use. But many other methods don't need to be static. By making them nonstatic, you give yourself more flexibility to modify things later. For example, for unit testing it's often useful to replace some method implementations with something simpler (usually to avoid invoking other parts of the "real" application while attemting to test one part). This is usually done using mock objects. This technique only works for instance methods, because you can't override a static method.
Testing aside, as your application matures you may find other reasons why you might wish to change implementations of some parts. Logging is a good example. Typically you want to put log statements in a bunch of different classes. But as your application grows, you aren't always interested in logging all the classes the same way - you might be very interested in logging messages from a prticular package, and not at all interested in other packages. Maybe some things need to be logged to a file, and others to a console (or both). And your needs may very well change frequently, so you don't want to have to edit the code each and every time. If your log statements were all static, then you'd be stuck with them all using the same implementation and therefore all behaving the same way. Or if you implemented a Logger as a true singleton, with one and only one instance, then again, they'd all be using the same implementation - but at least you'd have an easier time changing the implementation (for all the log statements) without having to edit the existing logging code too much. But it's much more practical to use factory methods to simply request a Logger instance that's appropriate for the class you're in, e.g.
or even (if possible)
Here it's entirely possible that the underlying implementation is a singleton. Or maybe it's creating a new instance each time. Or maybe it's got a nice elaborate way of creating a few instances at startup and looking up which one should be used in which context, based on some initialization properties somewhere. The important thing is, the clients almost never need to know or care. They just get an instance and use it. Whether or not it's a true singleton really doesn't matter. But the fact that it's an instance using nonstatic methods means it will be easy for you to change the underlying implementation later - maybe for all clients, or maybe just for some.
With this in mind, I would recommend something like the following, ahem, corrected version of the "singleton" from the first post above:
This is more or less a standard "singleton" without lazy instantiation. The thing is, we're not committed to keeping it a singleton. We can change it to something more elaborate later - e.g. a factory such as Kai shows. (Which can indeed be a good idea, but maybe it's more complex than we want initially.) The important thing is that we don't want a lot of client code that uses static methods here, because that's more work for us to change later. Maybe we'll change the way they call getInstance() later, and that may force some changes in client code. But at most that should be a change of one line per client file. That's much better than changing every line that uses a Util method. If we can avoid having to change the getInstance() code too, so much the better.
If we think we might eventually want something like Kai's factory suggestion above, probably the next improvement to make is to introduce the Validator interface. An interface can't have a static getInstance method, so we need at least one class besides the interface. I would do something lke this:
We may or may not add a factory of some sort later. Of maybe use lazy instantiation if that seems useful. But clients probably don't need to know anything about factories or lazy instantiation. They do need to know about the Validator interface. So we put that in before we put in any factories, so that clients will get used to using the Validator interface. Later we can put in a Factory if we want, and test code can put in a MockFactory, and other applications may find they need some other CustomFactory implementation. But the vast majority of clients can just keep calling Util.getValidator() to get the default implementation, without caring how it works. The goal is to first get the client interface stabilized as much as possible, then worry about changing the underlying implementation later if necessary to meet whatever other needs you may discover.
Having said all that... there are still times when I will just write a class with all static methods, no getInstance() methods or anything like that. That's often simplest, after all. I generally do it only in cases where I do not anticipate ever needing to mock out a method or provide an alternate implementation. Of course, I may be wrong in my anticipations, but it's a gamble - how much time should I spend creating additional infrastructure methods that I don't think will ever be used? If I gamble incorrectly, then well, I'll have more work later in refactoring. Oh well. I do know from experience that if I do need to refactor, I'll probably want to get rid of the static methods first, then add an interface, and then maybe think about a factory of some sort. So that's the order in which I consider putting those features at the beginning. If I know alternate implementations will be needed, I won't use static methods at all (but I still might not bother with the interface). How far you go down this road is up to you, and will probably vary from application to application, and from class to class. [ November 01, 2006: Message edited by: Jim Yingst ]
"Listen", said the mathematician who also happened to be well versed in this concept of 'computer programming', "I know it *looks* like your Java is programming computers, but I'm afraid that it is mathematically unsound and so your seemingly emotional attachment to this called a singleton is also unsound."
"Oh? Please tell...", said the Java novice.
"Aaaaah! the answer is right before you!", he said pointing to the book on the table.
"Oh all that theory stuff that has *nothing* to do with programming!!? No way!"
The mathematician offered a smile and a little nod as he ventured into his laboratory to write his paper titled, "Monads for the dummies who are inadvertently reinventing them several times per day".