Hi all, I have an interface - DataHandler that is implemented as DBDataHandler and LDAPDataHandler classes. Now, I want to have flexibility where I can switch between any of these two and so I am using Class.forName() where I can pass the class string dynamically. Here is what I do, DataHandler dh = (DataHandler)Class.forName(runtimehandler).newInstance(); dh.method1(); Finally, my problem is- I want to make these concrete handlers 'singleton' objects but I can't because if I want to use newInstance() then it has to have a public contructor in it, right? which makes 'singleton' idea fail... How to overcome this issue? Please help me to solve my dilema. Regards Maulin
Using reflection is the only approach to solve your dilemma Suppose you have a singleton class then you might be having a method to get its instance say getInstance() SO you can do Class cls = Class.forName(runtimehandler); Method metGetInstance = cls.getMethod("getInstance", null); DataHandler dh = (DataHandler)metGetInstance .invoke(null, null); dh.method1();
I can actually think of a couple of other ways to implement this. You could create "disposable objects"; that is: DataHandler dh = ((DataHandler)Class.forName(someName).newInstance()).getInstance(); This would create a "disposable" dh object, whose only purpose is to exist to ensure the correct class's "getInstance()" method is called. Probably not the greatest solution in the world, but it would work. Probably the better answer (albeit more complex) is to move the onus for returning the correct class to the DataHandler object itself (or, since it's an interface, to a "Factory" class).
And then in each of your subclasses you have a static initializer
Calling "Class.forName(className);" in the getInstance method ensures that the class gets loaded, ensuring that the static initialiazer is run, ensuring that there exists an instance in the instanceMap. To get the instance, you simply change your method calls from:
(Please note that this is how the JDBCDriverManager works; if you ever write a JDBC Driver, you have to include a static intializer to initialize it with the DriverManager) Hope that this helps. [ August 28, 2003: Message edited by: Joel McNary ]
Piscis Babelis est parvus, flavus, et hiridicus, et est probabiliter insolitissima raritas in toto mundo.
I always think twice when reflection seems necessary. Sometimes it is, but often it is not. You could make a factory that returns handlers. It could use several strategies: 1) Create a single instance of every possible handler at startup and cache them in a map keyed by type. 2) Use Class.forName().etc() to create a handler the first time somebody asks for one, then cache that instance. This gives a single instance of a handler that is not really a singleton. 3) Reflection, etc. Options 2 & 3 allow new handler types with zero code changes, even user-installed types that the developer never heard of. Pretty cool.
A good question is never answered. It is not a bolt to be tightened into place but a seed to be planted and to bear more seed toward the hope of greening the landscape of the idea. John Ciardi
to abstract things even further, you can then make a DataHandlerResolver class that is basically a map from type to class name, and then pass that to the workfactory to initialize it. The DataHandlerResolver should just be a map that can load its values from a config file (like XML) so that you can update the config file without changing a line of code. I happen to use this xml-resolver-factory-object pattern all the time.
Maulin, as you can see there are many, many ways to do this (there are in fact much more than discussed here). But without more information, it's impossible to say which one would be right for you. So, tell us more: Why do you want to use reflection? Do you really have only this two implementations, or are there possibly more coming? Who will write those implementations? Why do you want to use something like Singleton?
The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
Joined: Nov 04, 2001
hi Ilja Sure, I see there are many ways. I would go the way Joel suggested. Actually I thought of what Joel suggested but I didn't think the way to avoid having public contructor which Joel addresses very smartly. I like it I was trying to look for "without reflection" solution to avoid unnecessary overhead. Stan, the way you suggest is correct again but as I want to avoid "named" reference which I would have to make by LDAPHandler, and DBHanlder constructors, it would not be the one applicable here. Also, in my case I would only have one object in the system , either LDAPHandler or DBHandler so I wouldn't want to create both of the objects. Phil, I am little dumb to get what exactly you mean and I'm looking forward to my NY visit long weekend , so it would be sometime I can research google and try to understand what you suggested before I can comeup with more questions to you Though, I thank all of you for your suggestions. Now to address Ilja's questions, 1. Why do you want to use reflection? - I would want to avoid it if possible as I believe that if there is the other approach (like what Joel points) then reflection might be more work in comparison. 2. Do you really have only this two implementations, or are there possibly more coming? Who will write those implementations? - I don't think there would be more but DB and LDAP are what I am considering right now. In future it might be XML file storage as well. I am not sure about that. - I will be the one defining,implementing the interface. Actually, for I'm such a rush that I made the constructors public and made things work for me 3. Why do you want to use something like Singleton? - The reason I want to use singleton is that my objects that I see as DBDataHandler and LDAPDataHandlers are sort of "manager" objects that communicates with database or ldap in backend to store things. I am planning to use stateless objects (basically passing around Context object for every request, if you know what I mean). One can argue then why not have static methods? Well, I don't know. As I mentioned, I am right now in such a rush of getting things done I can't think I may forget this whole singleton business and declare all static methods with passing Context object to operate upon... I will give more thoughts to suggestions here and let my mind be at little ease to "think" rather than blindly code and see what do I end up with.. Also, I might create Factory of "Desparate" objects, in comparison of suggested factory of single type of objects by Joel, as these DBDataHandler and LDAPDataHandler are going to be there for each aspect in the application. e.g. - User/Role/Group management - Access control - Application repository storage you know.... I would be back to senses after long weekends! Till then, nJoy! Regards Maulin
Hi Ilja I read DataHandler from a file called something.properties and there I write, DataHandler DBDataHandler or DataHandler LDAPDataHandler then I read this properties file and load the class that is assigned to DataHandler property.. So, whenever I would change this properties file it will change the implementation handling to DB or LDAP accordingly. Regards Maulin