Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 2 of 3
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.
There's another problem. What if our Chef needs to build several different types of Meals (e.g. breakfast, TexMex, Happy)
from the same inventory? And what if we need to allow for the possibility that our Chef will move to a new restaurant where
they'll have to add even more Meals to their repertoire? Now you have to implement something like a Builder/Factory and your
buildMeal() method will become hopelessly complex and difficult to maintain. Sure, you can split it up into lots of private "buildXMeal"
methods, but at what point does your Chef morph into the dreaded God Object? Do you really want to find out? Me neither.