|
Jakarta main
Avalon main
Essentials
Guide
Reference
For Developers
|
Avalon Framework - Guide - OOP best practices
Avalon Framework - Guide - OOP best practices
|
by Leo Simons
Introduction |
While Avalon is not really about Object-Oriented Programming (OOP)
(we go much further), some of its concepts are important in
any programming project, so we summarise the 12 rules for code reuse
as given in
"Designing Reusable Classes"
by Ralph E. Johnson and Brian Foote (an excellent book).
Note that a good knowledge of the basic OOP concepts is a requirment for
understanding any of this. Many books deal with this, one that is freely
available online is
"Thinking in Java"
by Bruce Eckel (also a recommended read).
|
Recursion Introduction |
Use the same interface for communication with components of
the same type. It allows the swapping of those components
for other components of the same type without breaking existing
code.
If you need additional functionality, either create proxy
objects that implement the interface, or add it by subclassing
(hence the name "Recursion Introduction". Even if
there is no recursion happening, it appears to operate in the
same manner.
|
Eliminate Case Analysis |
Avoid testing to see if an object is an instance of a particular
class. Usually, if you think you need that approach then a
redesign will help immensely.
|
Reduce the Number of Arguments |
Methods with a half-dozen arguments are hard to read, and can
usually be accomplished with an object that represents that
set of arguments. It also makes it easier to track down the
problems.
|
Reduce the Size of Methods |
Most of your methods should only need to be a few lines long.
Methods that are very long (like 50 lines or so) are too complex,
and should be considered guilty of bad design until proven
innocent.
|
The Top of the Class Heirarchy Should be Abstract |
In many cases it is beneficial to provide an abstract base class
to extend for your specializations. The majority of the
functionality and behavior is well defined. This makes it easier
to decipher what the intents of the interface designer were.
|
Minimize Accesses to Variables |
This point formalizes the principles of data hiding. Try not
to expose class attributes to other classes, but protect them
by methods. If an attribute changes name, then you only have
one place to update the code instead of hundreds.
|
Subclasses Should be Specializations |
A [subclass] "is a" [superclass]. If what you
are trying to do is make a Component into a ComponentManager,
then you are violating the spirit of the framework. A better
approach is to use containment in that case (i.e. a [class]
"has a" [external class]).
|
Split Large Classes |
If a class has 50+ methods, then it is most likely trying to
do too much. Look at separating the functionality into
separate components. Like methods that are too long, classes
that violate this rule should be considered guilty of wrong
design until proven innocent.
|
Factor Implementation Differences Into Subcomponents |
If a subclass implements a method completely different from
the superclass, then it is not really a specialization. It
should be split off from that class hierarchy tree.
|
Separate Methods that Do Not Communicate |
Sometimes in building a framework you run into a case where
you have different views of the same data. In these cases,
you can have some attributes that describe how to generate
the data, and some attributes that describe the data itself.
It is better to separate these two views into separate classes.
The semantics are different enough to justify this solution.
|
Send Messages to Components instead of to This |
The point of this point is that you want to build your framework
based on Components, and not inheritance. Avalon takes this
point to heart. In order to illustrate, I will give two examples
of the same thing. The scenario is that we have a data structure
that we want to output to an arbitrary format.
In the following example, we will use the java this
object and an inheritance based framework. As you can see, this
would be a bear to maintain, and it won't easily be extended.
abstract class AbstractExampleDocument
{
// skip some code ...
public void output(Example structure)
{
if( null != structure )
{
this.format( structure );
}
}
protected void format(Example structure);
}
|
In the next example, we will use the Avalon Component based
architecture. There is a clean separation between the purpose
of the objects, and you can exchange and extend formatting
without worrying about any other concerns.
class DefaultExampleDocument
{
// skip some code ...
public void output(Example structure)
{
ExampleFormatter formatter =
(ExampleFormatter) manager.lookup(Roles.FORMATTER);
if( null != structure )
{
formatter.format(structure);
}
}
}
|
An inheritance based framework (White Box) can be converted
into a component based framework (Black Box) structure by
replacing overridden methods by method calls (message sends)
to components. Component based architecture is much more
flexible in this regard.
|
Eliminate Implicit Parameter Passing |
Just because two methods share the same information within the
class does not mean that it should be done in that manner.
Many times, that attribute that is shared should be passed
as a parameter of the method instead of directly accessing
the attribute.
|
|