Chapter 7. The Builder Pattern

In this chapter we'll consider how to use the Builder pattern to construct objects from components. We have already seen that the Factory Pattern returns one of several different subclasses, depending on the data passed in arguments to the creation methods. But suppose we don't want just a computing algorithm, but rather a whole different user interface, depending on the data we need to display. A typical example might be your e-mail address book. You probably have both people and groups of people in your address book, and you expect the display for the address book to change so that the People screen has places for first and last names, company name, e-mail address, and telephone number.

On the other hand, if you were displaying a group address page, you'd like to see the name of the group, its purpose, and a list of its members and their e-mail addresses. You click on a person's name and get one display and click on a group's name and get the other display. Let's assume that all e-mail addresses are kept in an Address object and that People and Group classes are derived from this base class, as shown in Figure 7.1.

Both Person and Group are derived from Address.

Figure 7.1. Both Person and Group are derived from Address.

Depending on which type of Address object we click on, we'd like to see a somewhat different display of that object's properties. This is little more than just a Factory pattern because the objects returned are not simple descendents of a base display object, but rather totally different user interfaces made up of different combinations of display objects. The Builder pattern assembles a number of objects, such as display widgets, in various ways depending on the data. Furthermore, since Java is one of the few languages with which you can cleanly separate the data from the display methods into simple objects, Java is the ideal language to implement the Builder pattern.

An Investment Tracker

Let's consider a somewhat simpler case in which it would be useful to have a class build our GUI for us. Suppose that we want to write a program to keep track of the performance of our investments, for example, stocks, bonds, and mutual funds. We want to display a list of our holdings in each category so that we can select one or more of the investments and plot their comparative performances.

Even though we can't predict in advance how many of each kind of investment we might own at any given time, we want a display that is easy to use for either a large number of funds (such as stocks) or a small number of funds (such as mutual funds). In each case, we want some sort of multiple choice display so that we can select one or more funds to plot. If there is a large number of funds, we'll use a multichoice list box; if there are three or fewer funds, we'll use a set of check boxes. We want our Builder class to generate an interface that depends on the number of items to be displayed and yet have the same methods for returning the results.

Our displays are shown in Figure 7.2. The first display, Figure 7.2(a), contains a large number of stocks, and the second, Figure 7.2(b), a small number of bonds.

(a) Display of stocks showing the list interface and (b) display of bonds showing the check box interface.

Figure 7.2. (a) Display of stocks showing the list interface and (b) display of bonds showing the check box interface.

Now, let's consider how we can build the interface to carry out this variable display. We'll start with a multiChoice abstract class that defines the methods that we need to implement.

public abstract class multiChoice {
    //the abstract base class
    //from which the list box and check box choice panels
    //are derived
    private Vector choices;            //array of labels
    public multiChoice(Vector choiceList) {
        choices = choiceList;          //save list
    }
    //to be implemented in derived classes
    abstract public Panel getUI();     //return Panel of components
    abstract public String[] getSelected(); //get list
    abstract public void clearAll();        //clear all
}

The getUI method returns a Panel container that has a multiple choice display. The two displays we're using here—a check box panel and a list box panel—are derived from this abstract class.

class listBoxChoice extends multiChoice

or

class checkBoxChoice extends multiChoice

Then we create a simple Factory class that decides which of the following two classes to return:

public class choiceFactory {
    multiChoice ui;
    //class returns a Panel containing
    //a set of choices displayed by one of
    //several UI methods
    public multiChoice getChoiceUI(Vector choices) {
        if (choices.size() <=3)
            //return a panel of check boxes
            ui = new checkBoxChoice(choices);
        else
            //return a multiselect list box panel
            ui = new listBoxChoice(choices);
        return ui;
    }
}

In the language of Design Patterns, this simple factory class is called the Director, and each actual class derived from multiChoice is a Builder.

Calling the Builders

Since we're going to need one or more builders, we might call our main class Architect or Contractor. However, here we're dealing with lists of investments, so we'll just call it wealthBuilder. In this main class, we create the user interface, consisting of a BorderLayout with the center divided into a 1-×-2 GridLayout.

The left part of the grid contains our list of investment types and the right an empty panel that we'll fill depending on the kinds of investments selected.

public class wealthBuilder extends JxFrame
  implements ListSelectListener, ActionListener {
     private JawtList stockList;              //list of funds
     private JButton Plot;                   //plot command button
     private JPanel choicePanel;             //right panel
     private multiChoice mchoice;            //ui for right panel
     private Vector Bonds, Stocks, Mutuals;  //3 lists
     private choiceFactory cfact;            //the factory

     public wealthBuilder() {
       super("Wealth Builder");            //frame title bar
       setGUI();                           //set up display
       buildStockLists();                  //create stock lists
       cfact = new choiceFactory(          //create builder factory
}

//--------------
  private void setGUI() {
      JPanel jp = new JPanel();
      getContentPane().add (jp);
      jp.setLayout(new BorderLayout());
      JPanel p = new JPanel();
      jp.add("Center", p);

      //center contains left and right panels
      p.setLayout(new GridLayout(1,2));
      stockList= new JawtList(10)          //left list of stocks
      stockList.addListSelectionListener(this);
      p.add(stockList);
      stockList.add("Stocks");
      stockList.add("Bonds");
      stockList.add("Mutual Funds");
      stockList.addListSelectionListener(this);

      JPanel p1 = new JPanel();
      p1.setBackground(Color.lightGray);
      jp.add("South", p1);
      Plot = new JButton("Plot");
      Plot.setEnabled(false);              //disabled until picked
      Plot.addActionListener(this);
      p1.add(Plot);
                                          //right is empty at first
      choicePanel = new JPanel();
      choicePanel.setBackground(Color.lightGray);
      p.add(choicePanel);

      setBounds(100, 100, 300, 200);
      setVisible(true);
}

In this simple program, we keep our three lists of investments in three Vectors—Stocks, Bonds, and Mutuals. We load them with arbitrary values as part of program initializing.

      Vector Mutuals = new Vector();
      Mutuals.addElement("Fidelity Magellan");
      Mutuals.addElement("T Rowe Price");
      Mutuals.addElement("Vanguard PrimeCap");
      Mutuals.addElement("Lindner Fund");

In a real system, we'd probably read them in from a file or database. Then, when the user clicks on one of the three investment types in the left list box, we pass the equivalent Vector to our Factory, which returns one of the Builders:

private void stockList_Click() {
    Vector v = null;
    int index = stockList.getSelectedIndex();
    choicePanel.removeAll(); //remove previous gui panel

    //switches between three different Vectors
    //and passes the selected one to the Builder pattern
    switch (index) {
    case 0:
        v = Stocks; break;
    case 1:
        v = Bonds; break;
    case 2:
        v = Mutuals;
    }
    mchoice = cfact.getChoiceUI(v);     //get one of the guis
    choicePanel.add(mchoice.getUI());   //insert on right
    choicePanel.validate();             //re-layout and display
    choicePanel.repaint ();
    Plot.setEnabled(true);              //allow plots
}

We show this switch code for simplicity. We could just as easily have attached adifferent ActionListener to each of the three buttons. We do save the multiChoice panel that the factory creates in the mchoice variable so that we can pass it to the Plot dialog.

The List Box Builder

The simpler of the two builders is the list box builder. The getUI method returns a panel containing a list box showing the list of investments.

public class listBoxChoice extends multiChoice {
    JawtList list;
//--------------
    public listBoxChoice(Vector choices) {
        super(choices);
    }
//--------------
    public JPanel getUI() {
        //create a panel containing a list box
        JPanel p = new JPanel();
        list = new JawtList(choices.size());
        list.setMultipleMode(true);
        p.add(list);
        for (int i = 0; i < choices.size(); i++)
            list.add((String)choices.elementAt(i));
        return p;
    }

The other important method is the getSelected method, which returns a String array of the investments that the user selects.

public String[] getSelected() {
        String[] slist = list.getSelectedItems ();
        return(slist);
}

The Check Box Builder

The Check box Builder is even simpler. Here we need to find out how many elements are to be displayed and then create a horizontal grid of that many divisions. Then we insert a check box in each grid line.

public class checkBoxChoice extends multiChoice {
    //This derived class creates
    //vertical grid of check boxes
    int count;                        //number of check boxes
    JPanel p;                         //contained here
//--------------
    public checkBoxChoice (Vector choices) {
        super(choices);
        count = 0;
        p = new JPanel();
    }
//--------------
    public JPanel getUI() {
        String s;
        //create a grid layout 1 column x n rows
        p.setLayout(new GridLayout (choices.size(), 1));
        //and add labeled check boxes to it
        for (int i = 0; i< choices.size(); i++) {
            s =(String)choices.elementAt(i);
            p.add(new JCheckBox(s));
            count++;
        }
        return p;
    }

This getSelected method is analogous to the method shown previously and is included in the example code on the CD-ROM. We illustrate the final UML class diagram in Figure 7.3.

The Builder class diagram.

Figure 7.3. The Builder class diagram.

Consequences of the Builder Pattern

Using a Builder pattern has the following consequences:

  1. A Builder pattern lets you vary the internal representation of the product that it builds. It also hides the details of how the product is assembled.

  2. Each specific Builder is independent of any others and of the rest of the program. This improves modularity and makes the addition of other Builders relatively simple.

  3. Because each Builder constructs the final product step by step, depending on the data, you have more control over each final product that a Builder constructs.

A Builder pattern is somewhat like an Abstract Factory pattern in that both return classes made up of a number of methods and objects. The main difference is that while the Abstract Factory returns a family of related classes, the Builder constructs a complex object step by step depending on the data presented to it.

Thought Questions

  1. Some word processing and graphics programs construct menus dynamically based on the context of the data being displayed. How could you use a Builder effectively here?

  2. Not all Builders must construct visual objects. For the personal finance industry, what could you construct using a Builder? Suppose that you are scoring a track meet made up of five to six different events. How can you use a Builder in such a situation?

Programs on the CD-ROM

Program Description
BuilderwealthBuilder.java Constructs the last box and check box multiple choice panels discussed in this chapter.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset