Some reader favorites:
EJB fundamentals and session beans
Create a scrollable virtual desktop in Swing
Wizard API updated!
Tim Boudreau has released a new version of the Swing Wizard library (version 0.997) that fixes the WizardException bug reported in JavaWorld's recent Open Source Java Project profile. The article's examples have been reworked to test out the new, improved WizardException. Thanks, Tim, for this helpful fix!
Open Source Java Projects: The Wizard API
Some language features are just plain ugly. The first time you see them, you say to yourself, "If I ever have to use that, there's something wrong with my design." And most of the time you'd be right. Languages tend to be designed to fit the greatest common factor, which widens their appeal. Only problem is there's a lot of bad design in that GCF.
Enter Java nested classes. The first time I laid eyes on these, I couldn't imagine a single use for them that I wouldn't prefer to implement some other way.
Then I noticed something very unique about the way Java handles nested classes. Unless a nested class is declared as a static
member of its enclosing class, an instance of the enclosing class must exist before the nested class can be instantiated. For example: EnclosingClass.NestedClass nestedInstance = enclosingInstance.new NestedClass();
Those of you familiar with the Builder Pattern may already be thinking what I was. That enclosing class looks a lot like a Builder with the nested class as its Product! It turns out that an enclosing class can indeed be used in this way. In some cases, it can even provide stronger encapsulation compared to a traditional Builder implementation. In this article we're going to find out how by exploring three examples of implementing run-time composition for a given Product.
The simplest approach is to let the Product build itself. You can achieve run-time composition by passing an inventory of parts to the constructor. The Product can then decide what parts to use based on availability and some internal rules. Suppose, for example, you want to build meals. A meal is composed of courses which can vary by type (e.g. steak versus fish) and number (e.g. 7 courses versus 3). Your Product interface might look something like this:
package enclosingclassasbuilder;
public interface Meal {
String nextCourse(); //consume the next course
}
Next you need an inventory of parts. For brevity's sake let's just whip up something simple and obtuse:
package enclosingclassasbuilder;
import java.util.ArrayList;
public class Refrigerator {
public ArrayList<String> inventory = new ArrayList<String>();
}
Now you can implement the Meal interface as a self-composing Product like so:
package enclosingclassasbuilder;
import java.util.ArrayList;
public class SelfComposingMeal implements Meal {
private ArrayList<String> courses = new ArrayList<String>();
public SelfComposingMeal(Refrigerator fridge) {
//rules for selecting entree
if( fridge.inventory.contains("steak") ) {
courses.add("steak");
fridge.inventory.remove("steak");
}
else if( fridge.inventory.contains("fish") ) {
courses.add("fish");
fridge.inventory.remove("fish");
}
//rules for selecting side
if( fridge.inventory.contains("potato") ) {
courses.add("potato");
fridge.inventory.remove("potato");
}
else if( fridge.inventory.contains("asparagus") ) {
courses.add("asparagus");
fridge.inventory.remove("asparagus");
}
//rules for selecting dessert
if( fridge.inventory.contains("cobbler") ) {
courses.add("cobbler");
fridge.inventory.remove("cobbler");
}
else if( fridge.inventory.contains("cake") ) {
courses.add("cake");
fridge.inventory.remove("cake");
}
}
public String nextCourse() {
if( !courses.isEmpty() ) return courses.remove(0);
return null;
}
}
While this implementation is very straightforward and easily extensible, it exhibits poor encapsulation. Passing an instance of Refrigerator to the constructor of SelfComposingMeal means that you've got a public or package public inventory floating around out there. Not only are you trusting your users to build their own Meals, you're giving them free access to your Refrigerator! What's to stop them from building a "lobsterfest" Meal that consumes all of your most expensive items in one sitting? Clearly, we need a better solution.
You want to restrict access to the inventory of parts used to build Meals. You'd also like to discourage your users from building their own Meals. Implementing a traditional Builder is a fine way to accomplish both. Let's start with the interface:
package enclosingclassasbuilder;
public interface Chef {
Meal buildMeal();
}
Hey, that was easy! Now let's put some meat on those bones. First we need a concrete Product for our concrete Builder to build:
package enclosingclassasbuilder;
import java.util.ArrayList;
public class ChefConstructedMeal implements Meal {
public ArrayList<String> courses = new ArrayList<String>();
public ChefConstructedMeal() {
}
public String nextCourse() {
if( !courses.isEmpty() ) return courses.remove(0);
return null;
}
}
Now we can implement our Builder:
package enclosingclassasbuilder;
public class NonEnclosingChef implements Chef {
private Refrigerator m_ChefsFridge = new Refrigerator();
public NonEnclosingChef() {
}
public NonEnclosingChef(Refrigerator fridge) {
while( !fridge.inventory.isEmpty() ) m_ChefsFridge.inventory.add( fridge.inventory.remove(0) );
}
public Meal buildMeal() {
ChefConstructedMeal meal = new ChefConstructedMeal();
//rules for building entree
if( m_ChefsFridge.inventory.contains("steak") ) {
meal.courses.add("steak");
m_ChefsFridge.inventory.remove("steak");
}
else if( m_ChefsFridge.inventory.contains("fish") ) {
meal.courses.add("fish");
m_ChefsFridge.inventory.remove("fish");
}
//rules for building side
if( m_ChefsFridge.inventory.contains("potato") ) {
meal.courses.add("potato");
m_ChefsFridge.inventory.remove("potato");
}
else if( m_ChefsFridge.inventory.contains("asparagus") ) {
meal.courses.add("asparagus");
m_ChefsFridge.inventory.remove("asparagus");
}
//rules for building dessert
if( m_ChefsFridge.inventory.contains("cobbler") ) {
meal.courses.add("cobbler");
m_ChefsFridge.inventory.remove("cobbler");
}
else if( m_ChefsFridge.inventory.contains("cake") ) {
meal.courses.add("cake");
m_ChefsFridge.inventory.remove("cake");
}
return meal;
}
}
This is definitely an improvement over our previous implementation. Now we can keep our inventory private and control how Meals are constructed. What's that you say? We still don't completely control how Meals are constructed since the class itself is publicly available? That's a good point. Notice too how we've had to make our Meal's courses publicly available so that our Chef can add to them. It seems our encapsulation problem has migrated and now our users are free to alter the Meals they receive.
Free Download - 5 Minute Product Review. When slow equals Off: Manage the complexity of Web applications - Symphoniq
![]()
Free Download - 5 Minute Product Review. Realize the benefits of real user monitoring in less than an hour. - Symphoniq