It struck me that a difficulty with using interfaces and factories in Java is that you need to know which factory goes with which interface. A naming convention can help here, but it might not be consistent.
Instead, I suggest that you annotate your interface, to know about a default implementation.
This immediately brings up "Interfaces shouldn't be bound to their implementations!!! This is unpure, evil code!!!". When you are navigating code, trying to find implementations for a particular interface can be annoying and time-consuming.
I have set out here the most cohesive way I can think of for finding out which class to use as a default implementation when all you have is an interface. It doesn't 'bind' the implementation to the interface. It neither 'binds' nor mentions the implementation. The interface 'knows about' a factory.
I experimented with non-annotation ways of doing this, such as static blocks in interfaces, xdoclet-based solutions (well, I thought about xdoclet), but I decided they were all ugly. I think what I have is the most elegant but pragmatic way.
Time for some code.
@DefaultFactory(BlobbyFactory.class)
interface Blobby
{
void doSomething();
}
This says that BlobbyFactory is the default factory for the Blobby interface.
So when you want a Blobby, you instantiate BlobbyFactory and call its newInstance method.
As a convenience, I wrote a Farm class that you can use as follows:
Blobby blobby=(Blobby)new Farm().newInstance(Blobby.class);
The reason newInstance is not a static method is that you may wish to override the default factory, in some part of your application.
So the unit testing part of your application might want a mock object instead of whatever BlobbyFactory gives you (actually a BlobbyImplementation in this case).
Farm farm=new Farm();
farm.setFactory(Blobby.class,new MockBlobbyFactory());
then elsewhere:
Blobby blobby=(Blobby)farm.newInstance(Blobby.class);
In effect, a Farm is a Map
CodeSOD: Magical Bytes
8 hours ago
5 comments:
Uhm, why not using spring or another ioc framework for managing factories and component lifecycle?
Because that adds more complexity than I need. I can learn a 3-class (well, one interface, one class, one annotation) API in a few seconds, but I would guess learning Spring would take a lot longer. I don't generally need my entire component lifecycle to be managed, just the construction of a component.
I don't know much about spring, maybe I'm assuming (ASS-U-ME) too much.
I thought spring was for J2EE, maybe I got confused.
First off, Spring is not just for J2EE. Secondly using Spring for this is frickin nuts. This is indicidive of the "Hey ma, I want to increment an integer" - "Well son, you've gota use spring!" for this.
As for needing to know what the "default" implementaion is, well why? Any decent IDE can show you very quickly what implementations you have. If you need to mock/stub out inteferaces for tesing, use mocks. If you genuinely have multiple implementations of an interface, then what is the default, and why does it matter?
> "Secondly using Spring for this is frickin nuts."
I thought so too, even in my state of ignorance.
> As for needing to know what
> the "default" implementaion is,
> well why? Any decent IDE can
> show you very quickly what
> implementations you have.
Because I don't want people who use the interface to *have to* know about the implementations. I can even keep the implementation package-private.
I could even keep my factory package-private in a 1.4-compatible version I made (the problem is that the annotation refers to the factory's class, not an instance, as annotation members can only be classes, enums, strings and some other similar things). But either way, the user of the interface just needs to know about Farm and my interface. Hopefully I can be pretty consistent and use Farm for everything that I do, thus reducing the number of API look-ups that the client programmer does.
Not everybody uses an IDE. I do use Eclipse most of the time, but at home I use vim, and when I use a machine outside my office I ssh in and use vim.
I often put the default implementation of an interface as a public static class in the interface itself. Sometimes that would get too messy, but often, for default implementations that don't encompass a lot, this imo is the neatest way to keep things structured.
Post a Comment