|
|
|
Sponsored Link •
|
|
Advertisement
|
Guidelines
To summarize the advice given in this article, here are four
guidelines:
Try to keep the types of your variables as high
up the inheritance hierarchy as possible.
This guideline encourages you to treat objects as generically as
possible, which in turn encourages you to take advantage of dynamic
binding and polymorphism. When the type of a reference is a supertype
of the actual class of the referenced object, the JVM will use dynamic
binding to locate the correct implementation of a method you invoke on
that reference.
Prefer polymorphism and dynamic binding over instanceof and downcasting.
This guideline encourages you to program in the object-oriented way,
letting polymorphism and dynamic binding work for you. A telltale sign
of code that is disobeying this fundamental rule of thumb is a series
of if-else statements doing instanceof
tests.
Prefer code that 'knows what's coming.'
This guideline counterbalances the above guidelines, stating that
although you should make the type of your variables as far up the
inheritance hierarchy as possible, you shouldn't make them so far up
that you can't use the object without downcasting. You should give
variables the type furthest up the inheritance hierarchy that still
offers the methods you need to manipulate the object. That very type is
the type of object you know is coming.
Use instanceof to ask 'What can you do for me?' and
downcasting to access the functionality.
When it comes time to ask the question, What can you do for me?
prefer instanceof over reflection. You may know you have a
reference to some subclass of Animal and may invoke
methods declared in Animal on that object. But you still
may want to also invoke playFetch() on the object if it is
a Dog. Rather than using reflection to look for a
playFetch() method, use instanceof to see if
the object really is a Dog. Or perhaps better yet, use
instanceof to see if the object implements the
PlaysFetch interface.
Once you determine that an object is an instance of some class or
interface in which you are interested, use downcasting -- not reflection --
to get at the interesting methods. For example, once you determine
you have an Animal object that implements the
PlaysFetch interface, don't use reflection to invoke
playFetch() on the Animal reference. Instead,
downcast the Animal reference to PlaysFetch,
and invoke playFetch on the PlaysFetch
reference.
In short, don't use reflection for mainstream designs. Use it only for things like bean builders, object serialization mechanisms, object inspectors and debuggers.
Next month
In next month's Design Techniques article, I'll talk
about designing with static members.
A request for reader participation
I encourage your comments, criticisms, suggestions, flames -- all kinds
of feedback -- about the material presented in this column. If you
disagree with something, or have something to add, please let me know.
You can either participate in a discussion forum devoted to this material or e-mail me directly at bv@artima.com.
About the author
Bill Venners has been writing software professionally for 12 years.
Based in Silicon Valley, he provides software consulting and training
services under the name Artima
Software Company. Over the years he has developed software for the
consumer electronics, education, semiconductor, and life insurance
industries. He has programmed in many languages on many platforms:
assembly language on various microprocessors, C on Unix, C++ on
Windows, Java on the Web. He is author of the book: Inside the Java
Virtual Machine, published by McGraw-Hill.
Reach Bill at bv@artima.com.
This article was first published under the name Design with Runtime Class Information in JavaWorld, a division of Web Publishing, Inc., January 1999.
|
Sponsored Links
|