Java Forum / First Aid / May 2005
static or not?
David Vanderschel - 20 May 2005 00:02 GMT There are many situations when one has a Class for which it only makes sense that a single instance be created in a given session. It seems to me that, in this situation, it does not really make much difference whether the Class's variables are declared as static or not. There is still only going to be one instance of each anyway. I have determined by experiment that such a program compiles and works the same either way. (I have encountered a couple situations where the compiler was not happy until I made a certain variable static because I had referenced it from a static context. But such situations are rare for me.)
My question: When you have the choice, which choice should you make? My guess is that static declarations may lead to more efficient code; but I have been unable to find any discussion of this issue. (Part of the problem here is that Sun's search on "static" hits just about everything. Its concept of relevance seems pretty weak.) If it makes no difference, then I see no point in cluttering the code with unnecessary "static" key words.
I could use some guidance on this issue.
Any pointers appreciated, David V.
iamfractal@hotmail.com - 20 May 2005 08:37 GMT > There are many situations when one has a Class for > which it only makes sense that a single instance be [quoted text clipped - 24 lines] > Any pointers appreciated, > David V. Hi, David,
When I need a single instance, I use a singleton (with a non-private constructor, admittedly), with a static getInstance() method and all other methods and data non-static.
I have no idea whether static data/methods lead to more efficient code, but I think if your application depends upon such efficiency gains then perhaps a non-interpreted language is better suited to your needs.
The minor reason I use as many non-static data/methods as possible is because it makes it slightly easier to subclass the class if I find that I was wrong in my assumption of the class's singularness, and that perhaps two specific variants of the class are more suitable. If it were a significant effort to use a singleton over using all static data/methods, then I wouldn't bother; but singletons are, I find, easy to design and use.
The major reason I use a singleton applies only when the singleton is declared as public, i.e., is accessible outside its package. Dependencies on concrete classes outside their home packages are more dangerous than dependencies on concrete classes within their home packages, as packages should be as encapsulated at possible/convenient. So I prefer to cite the first principle of OO ("Program to an interface not an implementation") when dealing with public classes, and try to access the services they offer via an interface (or an abstract class) rather than by the concrete class itself. Thus, I can alter the implementation of the concrete class without affecting its clients.
I generally do this by having the singleton register itself in a public Registry class. Yes, this is a concrete class visible to all packages, but I keep this class as simple as possible: it only stores and returns interface, and particluarly has no dependencies on the methods contained in those interfaces, so I can change the the entire set of methods within any given interface without changing the Registry code.
If I use a singleton, then I can strip away an interface from this singleton, and have it register that interface in the Registry.
If I use static methods, I cannot do this: static methods are not allowed to hide the instance methods of the interface.
This is the major reason I use a singleton, instead of a class of static methods.
.ed
www.EdmundKirwan.com - Home of The Fractal Class Composition.
hawat.thufir@gmail.com - 24 May 2005 04:20 GMT ...
> If I use a singleton, then I can strip away an interface from this > singleton, and have it register that interface in the Registry. [quoted text clipped - 4 lines] > This is the major reason I use a singleton, instead of a class of > static methods. ...
would expand on your thoughts here? instead of having, for example, a "driver" class you'd have a singleton?
thanks,
Thufir
iamfractal@hotmail.com - 25 May 2005 08:56 GMT Hi, Thufir,
Well, I'm not sure what you mean by a, "Driver," class, so I'll take a guess a guess at a definition: a Driver class is a class that coordinates a sequence of interactions with a number of other classes.
(If that's not what you meant, of course, then the rest of this post is irrelevant.)
I did not mean to imply that I would automatically make any such Driver class a singleton. Several instances of such a class may be required, in which case my reply to the OP does not hold.
If the application did, however, require one and only one Driver object to be instantiated, then I would have a small preference to using a singleton as opposed to a class of static methods, if this Driver was not accessible outside its package.
On a system-level, the package is generally the primary unit of encapsulation, as opposed to the class (though of course even class-level behaviour should be as encapsulated as possible); afterall, if you were presented with a presentation on a new system, would you rather be first presented with a web of 5,000 classes, or 40 packages?
Such being the case, the main reason for this small preference for a singleton would be the possibility that the Driver might, some day, be made accessible outside its package. While Driver is only visible inside one package, then having all the classes depend on the Driver's concrete class is not too big a problem, because the reason all these classes are packaged together is (presumably) that they have some commonality of purpose, for example, they all work to put a GUI on a screen. Thus it's possible that if there are new requirements on the GUI, the implementation of many classes within that package might be impacted, and the degree to which they can all be hidden from one another is limited.
If, however, the day comes that the Driver must be accessible outside the package, then there will suddenly be a strong preference for having Driver implemented as a singleton rather than a class of static methods.
If we continue with out example, the Driver that controls the display of the GUI is now being depended on by another package which (presumably) has nothing to do with GUI: it could, for example, be a Database class that wants to output a query result, but doesn't care whether the output is made to a GUI, a socket, a text file, etc.
If Driver were a class of static methods, then Databse would now need a dependency on the concrete class Driver. And as Driver only controls the GUI, then if Database wants to output to a text file, it must have some knowledge of other functionality that writes its output to that medium.
If Driver were a singleton, however, then, as mentioned, it could declare an interface (View) that is registered in a Registry that is known to Database. But all the other means of outputting data could also register that same interface to implement functionality for their own, specific medium. Thus TextView, FileView, and SocketView could all register their View interface in the Registry.
And when Database wants to write a result, it can ask Registry to return the currently-selected output medium implementation, hidden behind the View interface. This current selection could be controlled by a user option. Also, if there are new requirements on the GUI, such as the requirement that output should be made via Email to the CEO, this new view can be introduced to the system(e.g., EmailView) without impacting the Database functionality.
Now, I'm just waiting to see, "No, that's not what I meant by Driver ..."
.ed
www.EdmundKirwan.com - Home of The Fractal Class Composition.
hawat.thufir@gmail.com - 26 May 2005 10:39 GMT > Hi, Thufir, ...
> If Driver were a class of static methods, then Databse would now need > a dependency on the concrete class Driver. And as Driver only controls > the GUI, then if Database wants to output to a text file, it must have > some knowledge of other functionality that writes its output to that > medium. right, follow you there.
> If Driver were a singleton, however, then, as mentioned, it could > declare an interface (View) that is registered in a Registry that is > known to Database. But all the other means of outputting data could > also register that same interface to implement functionality for their > own, specific medium. Thus TextView, FileView, and SocketView > could all register their View interface in the Registry. ...
There'd be package "driverAndViews," or something, with the various view interfaces package private; or, the views would be nested within Driver. The view interfaces are registered in Registry to enable Database to send that e-mail to the CEO.
How does the communication between Database and Registry work?
> Now, I'm just waiting to see, "No, that's not what I meant by Driver ...
heh, not at all, spot on :)
-Thufir
iamfractal@hotmail.com - 26 May 2005 16:09 GMT > > Hi, Thufir, > ... [quoted text clipped - 5 lines] > > How does the communication between Database and Registry work? Hi, Thufir!
OK, lets aim this baby in the Model-View-Controller direction, and kill half a flock of birds with one stone.
In the previous email, I mistakenly showed Driver as implementing a View interface, but I will correct this in this example, and portray Driver as a Controller. Do forgive this changed point of view, but it should make the example more, "Real world."
It should forever strike you as odd when you hear a designer say, "I've used the MVC pattern to organise my classes for this problem," and then when you see the design there's no model package, no view package, and no controller package. A mistake we won't make as we embellish this example.
The first principle of OO states, as you know, "Program to an interface, not an implementation."
The theory we're discussing here can also be reduced to a shockingly similar principle, "Program to an interface repository, not an implementation repository."
We will hereby define an interface repository as a package containing at most one concrete class. An implementation repository is a package containing more than one concrete class.
Note that this theory was developed for industrial-sized systems, so looks overkill here, but it should get the point across.
We will split this example application into five packages: model, view, controller, start, and ir1. "ir1" is the standard name for the first interface repository. All these packages are usually peers (i.e., they have the same parent package). model, view, and controller will all be implementation repositories.
The start package is special: it contains just one class, Start, which holds the public static void main() method, and is responsible for triggering one public class in each of the three other implementation repositories. So, in the model package, there will be one public concrete class called, "ModelStart;" in the controller package, there will be, "ControllerStart," etc. Crucially, these XStart classes are the only public concrete classes in the implementation repositories; all other classes in the package will be package-private. These XStart classes then tell as many as necessary of the other, package-private contrete classes in the implementation repositories that the system has started, and they must register themselves in the registry.
The ir1 package will contain the singleton, concrete class Registry, and will also contain the View interface. (In fact, ir1 will contain *all* the interfaces visibile to all other packages; all the interfaces - as well as the Registry class - in ir1 will be public.)
The model package will contain, as well as ModelStart, the concrete, package-private class Database, which will implement the interface ir1.Model.
The view package will contain, as well as ViewStart, the package-private, concrete classes TextView, FileView, and SocketView, all of which will implement ir1.View.
The controller package will contain, as well as public class ControllerStart, the package-private concrete class Driver, which will implement ir1.Controller.
When the start.Start class's main() method is called, it will, as mentioned, contact all the other XStart classes, and they will order the relevant package-private implementation classes to register in the Registry. (Of course, in reality, only a few classes will need to register.)
Thus, for example, controller.Driver will register its Controller interface in the Registry by calling: Registry.getInstance().register(this).
Next, a user will make some input; we needn't specify how, here, but suffice it to say that when that input is made, an object will need to get that input into the system. It will do this by doing something like: Controller controller = Registry.getRegistry().getController(); controller.process(input);
The Driver object will have its process() method called, and will kick the database into life, by something like: Registry registry = Registry.getInstance(); Model model = registry.getModel(); model.doThis(); model.doThat(); Result result = model.getResult();
(OK, here's an interface I'd forgotten; any guesses where we'd declare it?)
The Driver object would then output the result to the use by: int viewID = registry.getCurrentViewID(); View view = registry.getView(viewID); view.show(result);
Thus we have a system in which there are only two types of inter-package, concrete class dependencies:
1) From Start to XStart - and these XStart classes only contain enough logic to kick start the business logic, in other words, these dependencies do not change as business logic changes.
2) Dependencies on the Registry concrete class - but this class simply stores and erturns interfaces, and has no dependencies on the methods of those interfaces, and thus is immune to changes of the interface methods (although of course will change as whole interfaces change, and new ones are added).
And *all* other inter-package dependencies are on interfaces only. Thus, you can switch in any database you like, as long as it conforms to the Model interface (this will, in reality, probably be JDBC, or a wrapper thereof). The same goes for the Views and even the Controller itself.
Hence, "Program to an interface repository, not an implementation repository."
Note that model package, view package, and controller packages do not depend on one another (you can Google for the heated discussions on which of these packages should depend on one another, and which must not), and that the system is guaranteed to be free from inter-package circular dependencies.
Of course a full system will have hundreds of packages, and there will be hierarchical start/implementation repository/irX packages, but the design is - and particularly the benefits listed above are - wonderfully extensible.
.ed
www.EdmundKirwan.com - Home of The Fractal Class Composition.
hawat.thufir@gmail.com - 27 May 2005 14:18 GMT Hi, Ed!
...
> Thus, for example, controller.Driver will register its Controller > interface in the Registry by calling: > Registry.getInstance().register(this). package controller; package-private class Driver extends controller.Controller{ void register() { Registry.getInstance().register(this); } } is the register method correct as far as it goes?
"If I use a singleton, then I can strip away an interface from this singleton, and have it register that interface in the Registry.
If I use static methods, I cannot do this: static methods are not allowed to hide the instance methods of the interface.
This is the major reason I use a singleton, instead of a class of static methods. " -Ed
this is where you're stripping away an interface?
> Next, a user will make some input; we needn't specify how, here, but > suffice it to say that when that input is made, an object will need to > get that input into the system. It will do this by doing something > like: > Controller controller = Registry.getRegistry().getController(); > controller.process(input); if this is done from class foo, what's foo's package? of MVC I think view, but view presents data to the user, so I'm not sure.
> The Driver object will have its process() method called, and will kick > the database into life, by something like: [quoted text clipped - 6 lines] > (OK, here's an interface I'd forgotten; any guesses where we'd declare > it?) heh, ir1 of course.
> The Driver object would then output the result to the use by: > int viewID = registry.getCurrentViewID(); > View view = registry.getView(viewID); > view.show(result); where did result come from, please? view.show() might trigger a SQL query and would show the outcome of that query?
you said "...portray Driver as a Controller," so it's:
package controller; package-private class Driver implements SomeInterface {...
> Thus we have a system in which there are only two types of > inter-package, concrete class dependencies: > > 1) From Start to XStart - and these XStart classes only contain enough > logic to kick start the business logic, in other words, these > dependencies do not change as business logic changes. if everything in the start package is business logic, might that logic consist of static methods, like Math.sin(x), or is that a bit extreme?
> 2) Dependencies on the Registry concrete class - but this class simply > stores and erturns interfaces, and has no dependencies on the > methods of those interfaces, and thus is immune to changes of the > interface methods (although of course will change as whole > interfaces change, and new ones are added).
> And *all* other inter-package dependencies are on interfaces > only. Thus, you can switch in any database you like, as long as it [quoted text clipped - 10 lines] > not), and that the system is guaranteed to be free from inter-package > circular dependencies. err, next time ;)
> Of course a full system will have hundreds of packages, and there will > be hierarchical start/implementation repository/irX packages, but the [quoted text clipped - 4 lines] > > www.EdmundKirwan.com - Home of The Fractal Class Composition. this helps to justify MVC for me, thanks.
-Thufir
hawat.thufir@gmail.com - 27 May 2005 14:27 GMT > Hi, Ed! > [quoted text clipped - 9 lines] > } > } ...
err,
package controller; package-private class Driver implements ir1.Controller{ void register() { Registry.getInstance().register(this); } }
iamfractal@hotmail.com - 31 May 2005 16:17 GMT > Hi, Ed! > [quoted text clipped - 21 lines] > > this is where you're stripping away an interface? Exactly, though I should have pointed out the signature of this method, as it is crucial. This method will have signature:
void register(Controller controller);
And not, void register(Driver controller);
This any Driver implementation could register, as long as it implements the Controller interface. This would not be possible if we tried to register a class of static methods.
> > Next, a user will make some input; we needn't specify how, here, but > > suffice it to say that when that input is made, an object will need to [quoted text clipped - 5 lines] > if this is done from class foo, what's foo's package? of MVC > I think view, but view presents data to the user, so I'm not sure. Well, class Foo, in this case, will be a class that captures user input, which is traditionally put in the controller package. As the user input could be from a button click (if the tool is started graphically) or from a class just reading command line input, these classes - specific to user input - are usually put in a subpackage of controller.
For example, controller.gui would hold the GUI widgets waiting for button clicks, and controller.cli would have classes reading from the command line.
In our small example, however, it would be perfectly acceptable to have all these user-input classes lumped into the controller package itself.
> > The Driver object will have its process() method called, and will kick > > the database into life, by something like: [quoted text clipped - 8 lines] > > heh, ir1 of course. Absolutely!
> > The Driver object would then output the result to the use by: > > int viewID = registry.getCurrentViewID(); [quoted text clipped - 4 lines] > view.show() might trigger a SQL query and would show the outcome of > that query? This is a continuation of the code written above; result is just a convenient way to pass view-independent data from controller to the view. The Driver code altogether will be:
Registry registry = Registry.getInstance(); Model model = registry.getModel(); model.doThis(); model.doThat(); Result result = model.getResult(); int viewID = registry.getCurrentViewID(); View view = registry.getView(viewID); view.show(result);
Here we see, again, that Driver has only one dependency one a concrete class, and all the rest are interfaces.
> you said "...portray Driver as a Controller," so it's: > > package controller; > package-private class Driver implements SomeInterface {... Correct, and that SomeInterface will actuall be the Controller interface.
> > Thus we have a system in which there are only two types of > > inter-package, concrete class dependencies: [quoted text clipped - 6 lines] > logic consist of static methods, like Math.sin(x), or is that a bit > extreme? I didn't phrase this well. I meant to say that everything in the start package is NOT dependent on business logic: all the start package knows is how to call a single method (usually start()) on one concrete class in some other subsystems. Admittedly, this method could of course be static, but I still use singletons for these (yes, the getInstance() is static in fact).
So our start package will contain on class which will look something like this:
class Start { public static void main(String[] args} ( ModelStart.getInstance().start(); ControllerStart.getInstance().start(); ViewStart.getInstance().start(); ) }
And thus all the subsystems get a change to register relevant objects in the registry before the user starts clicking things.
Note, in the real world, the start phase is usually more complicated, using either broadcasts of sequentially increasing phases (so that, for example, the Registry object starts in phase 1, the ConcreteModel registers in phase 2, Driver registers in phase 3, etc.) or Observers all register to be notified of registrations together, and a first registration triggers a wave of registering throughout the system.
> > 2) Dependencies on the Registry concrete class - but this class simply > > stores and erturns interfaces, and has no dependencies on the [quoted text clipped - 31 lines] > > -Thufir
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|