Re: Singleton Pattern - practical alternatives?
Chris Uppal wrote:
Mark Jeffcoat wrote:
First, because Singletons are Global Variables, returned from
the grave where we tried to bury them so many years ago.
I often read this, but I don't think there's an ounce of truth in it.
I confess, I'm a little surprised. I thought I was making
a claim on a similar level to "breathing is useful".
Yes, I understood that. Which is why I phrased my introductory remark rather
more strongly than was actually justified ;-)
First, it's not clear to me how I'm supposed to tell the
difference between globals done right, and "spaghetti data".
.... <snippage> ...
Would you care to take a stab
at offering a few guidelines on how to recognize and avoid
spaghetti data?
<snip handy rules of thumb>
As someone relatively new to Java I can see the sense in what you are
saying but I can't see how else to implement certain things.
I think I have three or more areas where I'm either using singletons,
where singletons would be useful, or where I am doing something that I
think is related (but I may be misunderstanding) Maybe someone could
suggest best practice for some or all of these? ...
1) Constants that are used in several classes. In one case these are key
values for user preferences that I am storing in a properties file. For
example 'static String WINDOW_SIZE = "window_size";'. By using the
constant, the compiler will pick up any typing errors, If I type
'prop.get("window-size");' I'll not get a compiler error, may not get a
run-time error but will get unexpected behaviour. So in my class that
contains my main() I define these as static constants. Elsewhere I use
these constants as prop.get(MainClass.WINDOW_SIZE) etc. These are
clearly global, I don't see a cleaner alternative.
2) Shared single resources. My example is a database connection. My app
opens one connection, various classes use this to perform SQL
transactions on unrelated tables etc. I could add a `connection`
variable to every method call, but this makes for long strings of
arguments to method calls, in some cases just so the variable can be
passed on to other method calls (covered in Chris's rules of thumb).
So I have a singleton to create the connection and it provides a public
DBClass.getConnection() to return the connection. Obviously I have to be
careful to avoid concurrent use of the connection. I don't know of a
better way to share a single resource of this sort - is there one?
3) An "owner" for JDialogs. My App has a single frame. Many classes need
to popup modal Dialogs or JOptionPanes, these need an owner to be
specified. Currently I'm passing it as a parameter to the constructor of
any class that needs it. I'm not entirely happy with this approach. The
alternative seems to have a static variable MainClass.frame. Is there a
better approach?
4) As an aside to the above, I sometimes need various classes to be able
to things done by the main class, for example, update a status message
at the bottom of the main window. To achieve this I pass a reference to
the main JFrame in the constructor of classes created. So sometimes I
have ...
class Mainform extends JFrame {
Mainform() {
...
FooClass f = new FooClass(this);
BarClass b = new BarClass(this);
...
}
public void setStatus(String text) { ... }
}
class FooClass {
JFrame parent; // *** Note "JFrame" ***
FooClass(JFrame parent) {
this.parent = parent;
}
xyzzy() {
...
JOptionPane.showMessageDialog(parent, "Error" ...);
...
}
}
class BarClass {
Mainform parent; // *** Note "Mainform" ***
BarClass() {
this.parent = parent;
}
plugh() {
...
parent.setStatus("Important thing accomplished");
...
JOptionPane.showMessageDialog(parent, ...);
...
}
}
Having a Mainform variable in the constructor of BarClass means I can't
re-use the BarClass in another application. I also have this
JFrame/Mainform choice for parameter type that I find hard to resolve.
Any suggestions?
Sorry for droning on, I hadn't intended to be this wordy :-) Feedback
appreciated though.