Relax. You can (mostly) stop using Interfaces in Java now
garmhold.blogspot.com
garmhold.blogspot.com
What's the perceived downside of using interfaces? That you end up with more files? That you dead-end into bare method declarations when browsing your code? Any others?
I just disagree with that; I think it's far better to have an interface you don't really need lying around than to be caught without one when you do need it.
As an example of a language that gets it right, look at python. You can write your orginal classes in the simplest possible way they could be written, and yet expand from there to just as much architecture as your problem needs without ever touching the users of the class.
As for the rest of it.. it's just a question of proper design. If you're just making a utility, you don't need any interfaces or factories. If you're making a module for something that's intended to be run with a half-dozen service dependencies, it's probably a good idea to design it in a way that said dependencies can be injected -- whether you're using spring or doing something more lightweight. That applies across languages, same deal in python.
My big point about python is that you can always inject the dependencies, and you don't have to spend any thought beforehand to achieve this. Java could go a long way here with just a few minor changes -- for example, remove "new", you get a new object by calling it's constructor, without any special operators. Allow shadowing of functions. This alone would end the factory madness -- in fact, factories are just an awful boilerplatey way to implement this. For example, if I have a class Foo that needs to instantiate Bar to function, and I want to inject a different bar for some tests (or something), in python I can just:
def make_test_foo():
Bar = DummyObjectConstructor
return Foo()
(this will of course occur only in local scope, so that other potential users in other threads are not going to be stuck with dummy objects against their will)To achieve the same in java, the way I was taught to was to design in a BarFactory for use when needed. In most cases, it's not going to be needed. But if you don't make it, boy are you going to be in a world of pain when you do need it, and half the world already depends on your class.
What really irks me about this, is that hotspot is perfectly capable of dealing with these kinds of things -- it is a really nice platform for this kind of dynamicity. Sun just used think that poor programmers are going to be confused when you hit them with too many high-level concepts, and refuses to add constructs like this. Which would be fine, except that the programmers invariably go on to develop their own ugly workarounds, like factories, because they need the power.
This I believe to be the big reason why python is so much faster to program in than java. I can program for the now, completely ignoring superfluous architecture when my programs consists of 3 files, with the knowledge that I can safely add it later when needed. The syntax and dynamic typing are just a nice extra.
As far as comments about the ugliness of Java in this regard, I couldn't agree more. However, Java is Java and Python is Python, etc. If you are working in Java, and a lot of people are and don't have the option of switching to something else (think corporate, where what is common and familiar is good), if you are committed to Java, then you must embrace its paradigms. Interfaces and implementation classes are one of those. Enjoy it without fuss and focus on the problem at hand. You'll lose less sleep that way.
Now for people who do lots of mock objects this rule doesn't help them out much, but my other rule is I don't overly separate my system for testing purposes. Sure there are times when you need a mock object for java mail or external services you need to mock out. But, doing it for every service you have is really a lot of work for questionable gain. This is predicated on practical experience rather than architecture theory. The reason you separate your system for testing is to find more bugs. I found that I wasn't finding anymore bugs by separating things than I was by testing it integrated. And, in fact I found more bugs in the integration of services than I would if I only tested them in separate form. Therefore, I stopped doing the extra work to separate them because the payoff was really too small to bother. It's been much more productive to think like this.
The second { starts an instance initialization block, which runs on each object when it is constructed - not sure if it's before or after the constructor - gonna guess before!
It's useful in this case as anonymous inner classes can't define constructors.