Re: abstract vs. final
On Thu, 06 Dec 2007 09:06:42 -0500, Todd <todd.heidenthal@lmco.com> wrot=
e:
Hello,
My buddy and I were talking about whether it is better to use abstract=
or final on a class with the following "attributes":
1. The class only contains static methods - hence there is no reason
for instantiating an object.
2. The class will not be extended.
These statements are known to be true.
I would subject first off: The documentation should be the first place o=
ne =
goes to figure out how to use a class. If you document the intended use =
=
case ("this class is not intended to be instantiated"), then you've clea=
r =
from users making expectations.
He feels that the class should be abstract due to the first
attribute. I say final due to the second attribute (maybe with a
protected empty constructor). Is there a middle ground that is
appropriate or is one more correct than the other?
A good IDE will probably issue an excessive/unused code warning for =
writing a constructor that never gets called. Of course, you can always =
=
add a @SupressWarnings, or just turn off that warning.
Does the object "work" if you instantiate it? Since presumably the resul=
t =
of "new MyObject()" is not much different from "new Object()", then the =
=
object "works" (meaning, to your knowledge, your instance methods won't =
=
throw Errors).
You should also ask yourself: how will these rules change in the next =
major revision of this class? What sort of support would that update nee=
d =
to offer your current version? If you might need to expose your class as=
=
subclassable for internal implementations in the future, then it's =
probably a good idea to mark the class final until that time.
From the other side of the table: In general, it is considered bad =
practice to call a static method like you would an instance method =
(myObject.staticMethod). Fortunately, when JUnit was designed (to pick o=
ne =
example), this principle wasn't followed to the letter, allowing the tes=
t =
developer to write
public void testMyMethod() throws Throwable {
assertEquals(55, MyClass.myMethod(5));
}
rather than the more verbose:
public void testMyMethod() throws Throwable {
Assert.assertEquals(55, MyClass.myMethod(5));
}
You might even want to go hogwild:
public void testMyMethod() throws Throwable {
MyClass MC=new MyClass(); //non-production constructor; alias for=
code =
clarity only
assertEquals(55, MC.myMethod(5));
}
This is of course a mute point with the "import static" mechanism in Jav=
a =
1.5, which is the preferred way to reference statics without the class =
prefix. Rather, consider this a scenario that should qualify as an =
exception from the general rule: being verbose is redundant, and henders=
=
the readability of the test's parameters and expected results.
Likewise, another developer could come across a routine using =
reflection/interrogation in a "bean-esk" way to do something useful:
public void remotelyCallFooMethods(Object o) throws Exception {
for (Method m : o.getClass().getMethods())
{
if (m.getName().startsWith("foo"))
executeOnRemoteHost(m, o);
}
}
/**
* calls m.invoke(o), but on a remotely attached VM. Supports both instan=
ce =
& static methods
*/
public Object executeOnRemoteHost(Method m, Object o)
Probably not useful for your type of static methods, but as this is a =
theoretical case, somebody might run into it.
So, with those points presented, I stick with declaring classes like the=
se =
"abstract". Other programmers still get to use "import static", for =
convenience. If the other fellow has a *really* compelling reason that I=
=
did not envision to instantiate this object, then it is only a =
inconvenience:
MyClass o=new MyClass() { };
And hopefully they scratched their head, revisited the docs, and were =
still convinced that there was a good reason to make an exception to a =
general rule.
This isn't a bet or anything, we are both trying to increase our
understanding of Java, object-oriented programming, and proper
programming techniques.
For technique, I would stick to the principle that writing additional co=
de =
for the express purpose of reducing functionality and/or limiting code =
reusability is wastefull. Error checking is great, just don't go out of =
=
your way to wall yourself off from unconsidered usecases with brick & =
mortar.
HTH,
-Zig