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 requirement 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).
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.
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.
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.
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.
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.
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.
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]).
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.
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.
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.
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.
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.
An inheritance based framework (White Box) can be converted into a component based framework (Black Box) structure by replacing overridden methods with method calls (message sends) to components. Component based architecture is much more flexible in this regard.
Just because two methods share the same information within the class does not mean that it should be done in that manner. Many times, the attribute that is shared should be passed as a parameter of the method instead of directly accessing the attribute.