Chapter 15 Builder Summary prepared by Kirk Scott 1.

108
Chapter 15 Builder Summary prepared by Kirk Scott 1

Transcript of Chapter 15 Builder Summary prepared by Kirk Scott 1.

Page 1: Chapter 15 Builder Summary prepared by Kirk Scott 1.

1

Chapter 15Builder

Summary prepared by Kirk Scott

Page 2: Chapter 15 Builder Summary prepared by Kirk Scott 1.

2

Design Patterns in JavaChapter 15

Builder

Summary prepared by Kirk Scott

Page 3: Chapter 15 Builder Summary prepared by Kirk Scott 1.

3

Hairy Woodpecker

• From Wikipedia, the free encyclopedia• (Redirected from Hairy woodpecker)

Page 4: Chapter 15 Builder Summary prepared by Kirk Scott 1.

4

Page 5: Chapter 15 Builder Summary prepared by Kirk Scott 1.

5

The Introduction Before the Introduction

• All patterns occur in some context• The book’s example occurs in the context of

parsing• Parsing overall is not a small topic, so

explaining the background takes up some time• I also present an example where input comes

through a GUI rather than through parsing

Page 6: Chapter 15 Builder Summary prepared by Kirk Scott 1.

6

Builder

• One explanation for the use of the builder class is that at a given time, not all of the information needed (construction parameters) may be available to do construction

• Construction parameters may have to be parsed from some input string

• Or they may come in from some kind of user interface

• Actual construction has to be delayed

Page 7: Chapter 15 Builder Summary prepared by Kirk Scott 1.

7

• Another explanation for using the Builder design pattern is that construction can be moderately complicated in some cases

• Instead of cluttering up the class code with these complexities, you want to have the class contain just the normal methods and simple constructors

• You can offload the more complex versions of construction into a builder class

Page 8: Chapter 15 Builder Summary prepared by Kirk Scott 1.

8

• Specifically, construction can become complicated when you want to validate input parameters

• The builder design pattern is more than just an input verification pattern

• However, a simple way of understanding how it was developed and a case where you would want to apply it is to remember that it is a pattern which supports input verification for construction

Page 9: Chapter 15 Builder Summary prepared by Kirk Scott 1.

9

Book Definition of Pattern

• Book definition:• The intent of the Builder pattern is to move

the construction logic for an object outside the class to be instantiated.

• Comment mode on:• By definition, construction is being offloaded.• Offloading also makes it possible for actual

construction to be delayed.

Page 10: Chapter 15 Builder Summary prepared by Kirk Scott 1.

10

Ordinary Construction

• An ordinary constructor expects all of the construction parameters to be available at the time the constructor is called

• For an ordinary constructor:– The construction parameters have to exist– They should be valid/contain valid values

Page 11: Chapter 15 Builder Summary prepared by Kirk Scott 1.

11

Constructing when not all Parameters are Available

• In the book’s parsing example, the construction parameters have to be extracted from a String

• Not all parameters will be available up front• The builder is an intermediate object that can

hold input values until all are available to construct the base object desired

Page 12: Chapter 15 Builder Summary prepared by Kirk Scott 1.

12

The Fireworks Reservation Example

• The book paints the following scenario:• Suppose reservations for fireworks shows are

submitted as text strings like this example:• Date, November 5, Headcount, 250, City, Springfield, DollarsPerHead, 9.95, HasSite, False

Page 13: Chapter 15 Builder Summary prepared by Kirk Scott 1.

13

• The syntax of the input string is clear• Items are separated by commas• The order may be important, or the fact that

each value is preceded by a label/variable name may mean that there is flexibility in the order

Page 14: Chapter 15 Builder Summary prepared by Kirk Scott 1.

14

Why a Builder Might Be Useful

• Two simple approaches to the construction of a reservation object illustrate the difficulties you can encounter if you don’t use the builder pattern

• 1. Suppose you used a default constructor to construct an empty reservation

• Then, as the input string was parsed, set methods could be called to set the instance variable values

Page 15: Chapter 15 Builder Summary prepared by Kirk Scott 1.

15

• The shortcoming to this approach:• Midway through parsing you may encounter an

error, an invalid parameter value, or a missing parameter value

• If this could happen (and it could), the client code which parses and sets the values has to be written to handle such an error condition

• In other words, you would need to enclose the parsing and setting actions in if statements

Page 16: Chapter 15 Builder Summary prepared by Kirk Scott 1.

16

• 2. Alternatively, you could “save up” construction parameters, but without verifying them

• Then you could attempt to construct• Construction will fail, potentially

catastrophically, if input parameters are incorrect

Page 17: Chapter 15 Builder Summary prepared by Kirk Scott 1.

17

• Under this scheme you could try to write the constructor code to verify input parameters

• This approach leads to the same unpleasantness already encountered in some of the discussion of the singleton pattern

• A constructor that doesn’t successfully construct, which conceivably returns null, or more likely, throws an exception, is not highly desirable

Page 18: Chapter 15 Builder Summary prepared by Kirk Scott 1.

18

• The builder design pattern gets around the potential problems of both of the foregoing scenarios

• Parsing and verifying are done before trying to construct

• This means you don’t have to try and verify or handle error conditions in client code and you also don’t have to put the verification code into the class constructor

Page 19: Chapter 15 Builder Summary prepared by Kirk Scott 1.

19

Responsibility

• Aspects of this design pattern can be described in terms of responsibility

• You don’t want to do ad hoc parsing and verifying in every client program

• The client shouldn’t be responsible for the base class

• On the other hand, this pattern is a step away from pure responsibility of the base class for itself

Page 20: Chapter 15 Builder Summary prepared by Kirk Scott 1.

20

• The builder pattern gives an organized way of putting the verification logic into a single class that can be re-used, without burdening the base class with these details

• In other words, the responsibility for construction, under these special circumstances where the input parameters need to be verified, one after the other, is put into the builder class

Page 21: Chapter 15 Builder Summary prepared by Kirk Scott 1.

21

The Book’s Example

• The UML diagram on the next overhead shows some of the classes that will be needed for the book’s overall design

Page 22: Chapter 15 Builder Summary prepared by Kirk Scott 1.

22

Page 23: Chapter 15 Builder Summary prepared by Kirk Scott 1.

23

• The example has a Reservation class– This is the base class that is ultimately to be

constructed• The example has a ReservationParser class– This class has a builder instance variable– Construction of an instance of parser takes an

instance of a builder as a parameter– This is how the builder instance variable is

initialized

Page 24: Chapter 15 Builder Summary prepared by Kirk Scott 1.

24

• The example has a ReservationBuilder class, which is abstract– It is abstract because it contains an abstract builder

method named build()– This is the method that actually constructs the

Reservation object– Before the example is complete, concrete builder

classes will be needed that implement this method– The implementations will contain a call to the

constructor for the Reservation class

Page 25: Chapter 15 Builder Summary prepared by Kirk Scott 1.

25

• The ReservationBuilder class, continued– The UML diagram illustrates another fundamental

thing about the book’s scenario– Not only has Reservation construction been

offloaded into build() in ReservationBuilder– The get and set methods for the Reservation class

are mirrored in the ReservationBuilder class– Even though not explicitly shown, the mirroring of

the set methods tells you that the instance variables of Reservation have also been mirrored

Page 26: Chapter 15 Builder Summary prepared by Kirk Scott 1.

26

Note

• A student once asked, why pass a builder in to the parser?

• Why not just construct the builder within the parser?

• The answer has to do with the fact that eventually there will be multiple concrete builder classes

• The client code gets to choose which kind of builder object to pass in for the parser to use

Page 27: Chapter 15 Builder Summary prepared by Kirk Scott 1.

27

The Plan of Action

• Making an instance of Reservation involves these steps:

• 1. First you create a Builder object (empty)• 2. Then you create a Parser object passing it

the builder object• 3. Then you call the parse() method on the

parser passing it the String which contains the information about a reservation

Page 28: Chapter 15 Builder Summary prepared by Kirk Scott 1.

28

• Inside the parse() method, you parse out the individual parameters

• Parsing can involve if statements, making sure that values parsed from the String are valid, but this isn’t yet the verification step for building a Reservation object

• As you get the values from the String, you call the set methods for these variables on the builder object

Page 29: Chapter 15 Builder Summary prepared by Kirk Scott 1.

29

• 4. At the end of the parse() method code you call the build() method on the builder

• The build() method verifies that the builder’s instance variable values are valid as construction parameters for a base class object

• If they are OK, the base class constructor will be called with these parameters

• Otherwise, the build() method will throw an exception

Page 30: Chapter 15 Builder Summary prepared by Kirk Scott 1.

30

• Note that it is the build() method that can throw an exception

• This is the place where ultimate responsibility for validating input has been offloaded to

• In other words, the ReservationBuilder class is now responsible for the verification of input parameters for Reservation construction

Page 31: Chapter 15 Builder Summary prepared by Kirk Scott 1.

31

Why is the ReservationBuilder Class Abstract?

• In general, a simple example scenario could have a concrete ReservationBuilder class with a concrete build() method

• However, you may want to build in different ways in different cases

• This leads the authors to develop several different builders with different characteristics

Page 32: Chapter 15 Builder Summary prepared by Kirk Scott 1.

32

• The idea is that building can take on a life of its own

• Once building takes on a life of its own, the pattern begins to make sense

• Each of the different building scenarios is implemented in its own builder class

Page 33: Chapter 15 Builder Summary prepared by Kirk Scott 1.

33

• You’re extracting construction logic from the constructor of the base class and implementing it in a separate class

• Just as a simple class can have multiple constructors—

• A class with more complicated construction conditions can have multiple builders

Page 34: Chapter 15 Builder Summary prepared by Kirk Scott 1.

34

• The alternative is to write constructor code with complex logic for a variety of different cases

• The base class begins to become responsible for “too much stuff”

• The builder approach is cleaner

Page 35: Chapter 15 Builder Summary prepared by Kirk Scott 1.

35

• Building, although closely related to construction, is not construction itself

• The responsibility for verifying construction parameters is encapsulated in separate classes devoted to that

• The base class is no longer fully responsible for itself

Page 36: Chapter 15 Builder Summary prepared by Kirk Scott 1.

36

What Does the ReservationParser Class Do in the Example?

• Before considering the concrete subclasses of the ReservationBuilder, it’s necessary to examine the role of the ReservationParser in the example

• Keep in mind that you need input parameters from somewhere, but that a parser isn’t intrinsically part of the pattern

Page 37: Chapter 15 Builder Summary prepared by Kirk Scott 1.

37

• Calling the parse() method on a ReservationParser object, passing it a String, s, is the first step towards constructing a reservation

• The parse() method tries to extract construction parameters for a reservation from the String s

• The String s is a comma separated list

Page 38: Chapter 15 Builder Summary prepared by Kirk Scott 1.

38

• The parse() method makes use of a method named split() from the String class

• A call to split() takes the form of s.split(“,”)• The call to split() returns an array of Strings,

known as tokens, which are the substrings of s which are separated by commas

Page 39: Chapter 15 Builder Summary prepared by Kirk Scott 1.

39

• The parse() method also makes use of formatting and parsing characteristics of the Date class

• Among the things that happens with dates is that a month and day are always pushed into the next year so that reservations are for the future, not the past

Page 40: Chapter 15 Builder Summary prepared by Kirk Scott 1.

40

• When constructed, the ReservationParser accepts a reference to a builder object

• The parse() method examines the tokens of the input String one-by-one

• If they appear to be of the right type, inside the parse() method the set() method for the corresponding Reservation instance variable is called on the builder object

Page 41: Chapter 15 Builder Summary prepared by Kirk Scott 1.

41

• Passing the reference to builder into the parser as a construction parameter allows calls to set() in the parse method to change the builder

• Then, after the call to parse(), the call to build() can be made on the changed builder object in the client code

• The code for the parse() method is shown beginning on the next overhead

Page 42: Chapter 15 Builder Summary prepared by Kirk Scott 1.

42

• public void parse(String s) throws ParseException• {• String[] tokens = s.split(",");• for(int i = 0; i < tokens.length; i += 2)• {• String type = tokens[i];• String val = tokens[i + 1];• if("date".compareToIgnoreCase(type) == 0)• {• Calendar now = Calendar.getInstance();• DateFormat formatter =

DateFormat.getDateInstance();• Date d = formatter.parse(val + ", “• + now.get(Calendar.YEAR));• builder.setDate(ReservationBuilder.futurize(d));• }

Page 43: Chapter 15 Builder Summary prepared by Kirk Scott 1.

43

• else if("headcount".compareToIgnoreCase(type) == 0)• builder.setHeadCount(Integer.parseInt(val));• else if("City".compareToIgnoreCase(type) == 0)• builder.setCity(val.trim());• else if("DollarsPerHead".compareToIgnoreCase(type) ==

0)• builder.setDollars(Double.parseDouble(val)));• else if("HasSite".compareToIgnoreCase(type) == 0)• builder.setHasSite(val.equalsIgnoreCase("true");•

• /******* Back in the good old days you couldn’t• end a sequence of if/else if statements without• a final else, but now you can, and that's the way• the code is given in the book. *******/• }• }

Page 44: Chapter 15 Builder Summary prepared by Kirk Scott 1.

44

What Could Go Wrong with Parsing?

• Parsing can go wrong basically if the input String s is flawed

• The list might not be correctly comma separated or some of the values might not be of the right type

• The parser doesn’t look beyond these kinds of problems

Page 45: Chapter 15 Builder Summary prepared by Kirk Scott 1.

45

What Do the Individual, Concrete Builder Classes Do?

• In general, the task of the individual builders is to build under constraints

• Constraints can be things like valid ranges for the values of construction parameters

• It is the builder classes that are designed to implement those kinds of constraints and be more or less forgiving of faulty input

Page 46: Chapter 15 Builder Summary prepared by Kirk Scott 1.

46

• In other words, given the construction parameters extracted from the input String by the parser, what can you do with them?

• Suppose that every reservation had to have a non-null date and city

• Or suppose, at a more fine-grained level, there have to be at least 25 people in the audience and the total bill has to be at least $495.95.

Page 47: Chapter 15 Builder Summary prepared by Kirk Scott 1.

47

• In support of these constraints, a builder class might contain these declarations:

• public abstract class ReservationBuilder• {• public static final int MINHEAD = 25;• public static final Dollars MINTOTAL = new Dollars(495.95);

• // …• }

Page 48: Chapter 15 Builder Summary prepared by Kirk Scott 1.

48

• Varying checks for validity can then be put into the build() method of the builder classes rather than the base class (or the parser)

• The UML diagram on the following overhead shows two concrete subclasses of the abstract class ReservationBuilder, one a forgiving builder and one an unforgiving builder

Page 49: Chapter 15 Builder Summary prepared by Kirk Scott 1.

49

Page 50: Chapter 15 Builder Summary prepared by Kirk Scott 1.

50

• In the ReservationBuilder classes the build() method either returns a reference to a newly constructed Reservation object

• Or it throws an exception, in this case a BuilderException

• The UnforgivingBuilder and the ForgivingBuilder differ according to the conditions under which they throw a BuilderException

Page 51: Chapter 15 Builder Summary prepared by Kirk Scott 1.

51

• It may be worth noting the following:• We don’t want to have constructors which

throw exceptions• In essence we’ve wrapped construction in a

build() method which can throw an exception in case of inability to construct

• It is far preferable to have a method like this which throws and exception rather than a constructor which can fail

Page 52: Chapter 15 Builder Summary prepared by Kirk Scott 1.

52

• Before considering the implementation of one of the builder classes, the book shows some code illustrating how the parser and a builder would be related

• It is given on the next overhead• It will be followed by commentary

Page 53: Chapter 15 Builder Summary prepared by Kirk Scott 1.

53

• public class ShowUnforgiving• {• public static void main(String[] args)• {• String sample = “Date, November 5, Headcount, 250” + “City,

Springfield, DollarsPerHead, 9.95” + “HasSite, False”;• ReservationBuilder builder = new UnforgivingBuilder();• try• {• new ReservationParser(builder).parse(sample);• Reservation res = builder.build();• System.out.println(“Unforgiving builder: “ + res);• }• catch(Exception e)• {• System.out.println(e.getMessage());• }• }• }

Page 54: Chapter 15 Builder Summary prepared by Kirk Scott 1.

54

• In the client, the builder is created up front• The parser is created, passing in the builder• parse() is then called on the parser, passing in

the string• Recall that inside the parse() method the set

methods are called on the builder object one-by-one

Page 55: Chapter 15 Builder Summary prepared by Kirk Scott 1.

55

• After the parsing is done, build() is called on the builder

• If the parameters weren’t right, the build() method will throw an exception

• If the parameters were all right, the build() method will construct a reservation object and return a reference to it

Page 56: Chapter 15 Builder Summary prepared by Kirk Scott 1.

56

• It is apparent that validation/verification is occurring

• Also, to put this in the same terms as the pattern was initially introduced:

• The end result of this collection of interrelated classes is that actual construction of the Reservation object is delayed

Page 57: Chapter 15 Builder Summary prepared by Kirk Scott 1.

57

• These are the critical lines of code:• ReservationBuilder builder = new UnforgivingBuilder();• try• {• new ReservationParser(builder).parse(sample);• Reservation res = builder.build();• System.out.println(“Unforgiving builder: “ +

res);

• Because the sample string is OK, this code will simply print out the message “Unforgiving builder: ” followed by the successfully built reservation

Page 58: Chapter 15 Builder Summary prepared by Kirk Scott 1.

58

• Challenge 15.2• “The build() method of the UnforgivingBuilder

class thows a BuilderException if the date or city is null, if the headcount is too low, or if the total cost of the proposed reservation is too low.

• Write the code for the build() method according to these specifications.”

Page 59: Chapter 15 Builder Summary prepared by Kirk Scott 1.

59

• Comment mode on:• In essence the build() method will turn out to

be a bunch of if statements potentially followed by construction of the desired reservation object.

Page 60: Chapter 15 Builder Summary prepared by Kirk Scott 1.

60

• Solution 15.2• “The build() method of UnforgivingBuilder

throws an exception if any attribute is invalid and otherwise returns a valid Reservation object.

• Here is one implementation:”• [See next overhead.]

Page 61: Chapter 15 Builder Summary prepared by Kirk Scott 1.

61

• public Reservation build() throws BuilderException• {• if(date == null)• throw new BuilderException(“Valid date not found”);• if(city == null)• throw new BuilderException(“Valid city not found”);• if(headcount < MINHEAD)• throw new BuilderException(“Minimum headcount is ”

+ MINHEAD);•

if(dollarsPerHead.times(headcount).isLessThan(MINTOTAL))• throw new BuilderException(“Minimum total cost is ”

+ MINTOTAL);• return new Reservation(date, headCount, city,

dollarsPerHead, hasSite);• }

Page 62: Chapter 15 Builder Summary prepared by Kirk Scott 1.

62

• Solution 15.2, continued.• “The code checks that date and city values are

set and checks that headcount and dollars/head values are acceptable.

• The ReservationBuilder superclass defines the constants MINHEAD and MINTOTAL.

• If the builder encounters no problems, it returns a valid Reservation object.”

Page 63: Chapter 15 Builder Summary prepared by Kirk Scott 1.

63

• Comment mode on:• In order to understand the build() method,

you have to remember how the parser and the builder are related.

• The parser is passed the builder• As the parser runs, it calls the set methods for

the parameters of the builder

Page 64: Chapter 15 Builder Summary prepared by Kirk Scott 1.

64

• After the parser is finished, these instance variables are either set to acceptable values or not

• In the build() method code, the if statements depend on the state that the parser left the instance variables of the builder object in

• End of Solution 15.2

Page 65: Chapter 15 Builder Summary prepared by Kirk Scott 1.

65

A Forgiving Builder

• The book completes its example by giving an implementation of the ForgivingBuilder class.

• In order to save some time, this will not presented.

• Instead, the rest of the overheads will cover a separate example which doesn’t rely on parsing.

Page 66: Chapter 15 Builder Summary prepared by Kirk Scott 1.

66

The Pattern at Its Most Basic

• It is true that you have to get base class construction parameters from somewhere

• However, forget the parser for the moment and assume that the parameters are simply available in the client code

• The client code would consist of the parts shown on the following overhead

Page 67: Chapter 15 Builder Summary prepared by Kirk Scott 1.

67

• Construct the builder object• Call the set methods on the builder object,

passing in the base class construction parameters

• Call the build() method on the builder object, in a try block

• The build() method verifies the construction parameters before calling the base class constructor

Page 68: Chapter 15 Builder Summary prepared by Kirk Scott 1.

68

Another Example

• An example based on cups will be given next• Input values have to come from somewhere• This example obtains construction values from a

listener in a graphical user interface rather than from parsing a string

• This example is more complicated (and realistic) than the simple summary given on the previous overhead

• However, it is simpler than the book example because it doesn’t involve parsing

Page 69: Chapter 15 Builder Summary prepared by Kirk Scott 1.

69

• Keep in mind what the pattern does• It offloads construction of an object of one

class to another class• That other class manages delayed

construction of the object

Page 70: Chapter 15 Builder Summary prepared by Kirk Scott 1.

70

• The code for these classes is given as the basis of the example:

• Cup.java and BuildFromTextFields.java.• The example will be completed with

implementations of these classes:• CupBuilder.java and ForgivingCupBuilder.java.

Page 71: Chapter 15 Builder Summary prepared by Kirk Scott 1.

71

• The basis for this example is that a Cup, the ultimate class of interest, has two instance variables

• They are String name (of owner) and int seedCount• The CupBuilder class has two String instance

variables• The ForgivingCupBuilder class inherits these• The build() method uses these inherited instance

variables to construct an instance of the Cup class.

Page 72: Chapter 15 Builder Summary prepared by Kirk Scott 1.

72

• The name of a Cup’s owner is a String, so the inherited instance variable that the builder works with is of the right type.

• The seedCount of a Cup is an int, so it's necessary to parse the String instance variable of the ForgivingCupBuilder class and turn it into an int before using it as a construction parameter for a Cup.

Page 73: Chapter 15 Builder Summary prepared by Kirk Scott 1.

73

• The ForgivingCupBuilder class implements the following logic:

• A. An instance of the Cup class can't be constructed without an owner.

• The build() method should throw an exception if the value for the owner is the empty String ("").

• This part of the building process is "unforgiving".

Page 74: Chapter 15 Builder Summary prepared by Kirk Scott 1.

74

• B. The build() method should forgive cases where the String value for the seedCount is the empty String ("").

• In this case, an instance of Cup should be constructed with a seedCount of 0.

Page 75: Chapter 15 Builder Summary prepared by Kirk Scott 1.

75

• The ForgivingCupBuilder class is not intended to solve all of the problems of faulty input.

• For example, the code does not deal with the case where a user enters a value for the seedCount field which would not parse as an int.

• It simply deals with the case where the user doesn't enter anything at all for the seedCount field.

Page 76: Chapter 15 Builder Summary prepared by Kirk Scott 1.

76

• The application maintains a list of cups that are created

• The application also includes a JTextArea for output, which records the success or failure of attempts to create cups and add them to the list

• A screenshot of the application is shown on the next overhead

Page 77: Chapter 15 Builder Summary prepared by Kirk Scott 1.

77

Page 78: Chapter 15 Builder Summary prepared by Kirk Scott 1.

78

• This logic of building closely parallels the book’s example, but with different classes

• This example is different from the book example because it is graphical in nature

• Rather than working with an input string, the example works with values that are entered into JTextFields in the application

Page 79: Chapter 15 Builder Summary prepared by Kirk Scott 1.

79

• For that reason, building is done without a separate parser class

• Specific Integer/String parsing does occur• Also, there have to be steps where the values

are acquired from the text fields and stored in the corresponding instance variables

• But this is done within the BuildListener class, part of the graphical user interface, not in a separate parser class

Page 80: Chapter 15 Builder Summary prepared by Kirk Scott 1.

80

• A UML diagram for the application is given on the following overhead

• Note how clicking the button triggers the listener that acquires the values needed for building

• It is also within the code for the listener that the builder is constructed and the call to the build() method is made on it

Page 81: Chapter 15 Builder Summary prepared by Kirk Scott 1.

81

Page 82: Chapter 15 Builder Summary prepared by Kirk Scott 1.

82

• The code for the example is given on the following overheads.

Page 83: Chapter 15 Builder Summary prepared by Kirk Scott 1.

83

• /* This is the class you’re actually constructing instances of. */

• public class Cup• {• private String ownersName;• private int seedCount;

• public Cup()• {• }

• public Cup(String ownersNameIn, int seedCountIn)• {• ownersName = ownersNameIn;• seedCount = seedCountIn;• }

• public void setOwnersName(String ownersNameIn)• {• ownersName = ownersName;• }

Page 84: Chapter 15 Builder Summary prepared by Kirk Scott 1.

84

• public String getOwnersName()• {• return ownersName;• }

• public void setSeedCount(int seedCountIn)• {• seedCount = seedCountIn;• }

• public int getSeedCount()• {• return seedCount;• }

• public String toString()• {• return ("Cup[ownersName=" + ownersName• + ", seedCount=" + seedCount + "]");• }• }

Page 85: Chapter 15 Builder Summary prepared by Kirk Scott 1.

85

• /* This is the class that contains all of the graphical machinery—as well as the building. */

• import java.awt.*;• import java.awt.event.*;• import javax.swing.*;• import java.lang.*;• import java.util.*;

• public class BuildFromTextFields• {• public static void main(String[] args)• {• BuildFrame myframe = new BuildFrame();• myframe.setVisible(true);• }• }

Page 86: Chapter 15 Builder Summary prepared by Kirk Scott 1.

86

• class BuildFrame extends JFrame• {• private BuildPanel myPanel;• private final int FRAMEW = 700;• private final int FRAMEH = 700;

• public BuildFrame()• {• setTitle("Build Frame");• setSize(FRAMEW, FRAMEH);•

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

• myPanel = new BuildPanel();• Container contentPane = getContentPane();• contentPane.add(myPanel, "Center");• }• }

Page 87: Chapter 15 Builder Summary prepared by Kirk Scott 1.

87

• class BuildPanel extends JPanel• {• private JTextField ownersNameField;• private JTextField seedCountField;• private JButton buildCupButton;• private String ownersNameString;• private String seedCountString;• ArrayList<Cup> listOfCups;• JTextArea myTextArea;

Page 88: Chapter 15 Builder Summary prepared by Kirk Scott 1.

88

• public BuildPanel()• {• listOfCups = new ArrayList<Cup>();• JLabel label1 = new JLabel("Owner's Name:");• ownersNameField = new JTextField("", 12);• JLabel label2 = new JLabel("Seed Count:");• seedCountField = new JTextField("", 4);• buildCupButton = new JButton("Create Cup");• BuildListener myButtonListener = new

BuildListener();•

buildCupButton.addActionListener(myButtonListener);• myTextArea = new JTextArea(12, 24);

• JScrollPane myScrollPane = new JScrollPane(myTextArea,

• JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);

Page 89: Chapter 15 Builder Summary prepared by Kirk Scott 1.

89

• JPanel subPanel1 = new JPanel();• JPanel subPanel2 = new JPanel();• JPanel subPanel3 = new JPanel();• JPanel subPanel4 = new JPanel();• JPanel subPanel5 = new JPanel();• JPanel subPanel6 = new JPanel();• subPanel1.add(label1);• subPanel2.add(ownersNameField);• subPanel3.add(label2);• subPanel4.add(seedCountField);• subPanel5.add(buildCupButton);• subPanel6.add(myScrollPane);• setLayout(new GridLayout(3, 2));• add(subPanel1);• add(subPanel2);• add(subPanel3);• add(subPanel4);• add(subPanel5);• add(subPanel6);• }

Page 90: Chapter 15 Builder Summary prepared by Kirk Scott 1.

90

• public void paintComponent(Graphics g)

• {• Graphics2D g2 = (Graphics2D) g;• super.paintComponent(g2);

• }

Page 91: Chapter 15 Builder Summary prepared by Kirk Scott 1.

91

• /* This is the listener attached to the button in the application. Clicking the button is supposed to construct a cup based on the values in the JTextFields. This is where the ForgivingCupBuilder is put into action. */

• private class BuildListener implements ActionListener

• {• public void actionPerformed(ActionEvent event)• {• ForgivingCupBuilder myBuilder;• Cup myCup = null;

• ownersNameString = ownersNameField.getText();

• ownersNameField.setText("");• seedCountString = seedCountField.getText();• seedCountField.setText("");

Page 92: Chapter 15 Builder Summary prepared by Kirk Scott 1.

92

• myBuilder = new ForgivingCupBuilder(ownersNameString, seedCountString);

• try• {• myCup = myBuilder.build();• }• catch(Exception buildException)• {• myTextArea.append("\nCaught build

exception.\n");• }

Page 93: Chapter 15 Builder Summary prepared by Kirk Scott 1.

93

• if(myCup != null)• {• listOfCups.add(myCup);• }

• myTextArea.append("\nLatest contents of listOfSeeds.\n");

• for(Cup aCup: listOfCups)• {• myTextArea.append(aCup.toString() + "\n");• }• }• }• }

Page 94: Chapter 15 Builder Summary prepared by Kirk Scott 1.

94

• /* This is the abstract CupBuilder superclass. It contains the declaration of the abstract build() method. */

• public abstract class CupBuilder• {• private String ownersName;• private String seedCountString;

• public CupBuilder()• {• }

• public CupBuilder(String ownersNameIn, String seedCountStringIn)• {• ownersName = ownersNameIn;• seedCountString = seedCountStringIn;• }

• public void setOwnersName(String ownersNameIn)• {• ownersName = ownersName;• }

Page 95: Chapter 15 Builder Summary prepared by Kirk Scott 1.

95

• public String getOwnersName()• {• return ownersName;• }

• public void setSeedCount(String seedCountStringIn)• {• seedCountString = seedCountStringIn;• }

• public String getSeedCountString()• {• return seedCountString;• }

• public String toString()• {• return ("CupBuilder[ownersName=" + ownersName• + ", seedCount=" + seedCountString + "]");• }

• public abstract Cup build() throws Exception;• }

Page 96: Chapter 15 Builder Summary prepared by Kirk Scott 1.

96

• /* This is the ForgivingCupBuilder class, which implements a forgiving version of the build() method. */

• import java.lang.Exception;

• public class ForgivingCupBuilder extends CupBuilder• {• public ForgivingCupBuilder(String ownersNameIn,

String seedCountStringIn)• {• super(ownersNameIn, seedCountStringIn);• }

Page 97: Chapter 15 Builder Summary prepared by Kirk Scott 1.

97

• public Cup build() throws Exception• {• int seedCount;• String ownersNameHere = this.getOwnersName();• String seedCountStringHere = this.getSeedCountString();

• if(ownersNameHere.equals(""))• {• throw new Exception();• }• else• {• if(!seedCountStringHere.equals(""))• {• seedCount = Integer.parseInt(seedCountStringHere);• }• else• {• seedCount = 0;• }• }

• return new Cup(ownersNameHere, seedCount);• }• }

Page 98: Chapter 15 Builder Summary prepared by Kirk Scott 1.

98

UML for the Pattern

• There is no single, official UML diagram that represents the builder pattern

• At a minimum the pattern involves some client, the builder class, and the base class of the actual object that is to be created

• Things like a parser, a graphical user interface, and a hierarchy of abstract and concrete builders are not parts of the fundamental concept.

Page 99: Chapter 15 Builder Summary prepared by Kirk Scott 1.

99

• A simple static structure diagram and a sequence diagram are given on the following overheads to illustrate the basic design pattern

Page 100: Chapter 15 Builder Summary prepared by Kirk Scott 1.

100

Page 101: Chapter 15 Builder Summary prepared by Kirk Scott 1.

101

Page 102: Chapter 15 Builder Summary prepared by Kirk Scott 1.

102

• If you went back to the overall UML diagram for the example you would find that the BuildListener inner class plays the role of the client

• The ForgivingCupBuilder class plays the role of the builder

• And the Cup class is the base class in the design• The rest of the classes in the example just belong

to the application’s graphical user interface

Page 103: Chapter 15 Builder Summary prepared by Kirk Scott 1.

103

• Lasater’s UML diagram is given on the next overhead.

• Using that author’s terminology, the pattern is recognizable by the use of the construct() method in the director class and the build methods in the builder classes.

Page 104: Chapter 15 Builder Summary prepared by Kirk Scott 1.

104

Page 105: Chapter 15 Builder Summary prepared by Kirk Scott 1.

105

(Book) Summary

• The Builder pattern separates the construction of an object from its other characteristics

• The builder class contains the construction logic, leaving the base class code simpler

• This can be useful when you want to make sure the construction parameters are valid before trying to construct an instance of a class

• The validity checking is offloaded into the builder class

Page 106: Chapter 15 Builder Summary prepared by Kirk Scott 1.

106

• The Builder pattern supports so-called step-by-step or gradual construction

• The builder object is constructed• Its instance variables are set step-by-step• Then if it is complete and correct, it can create

an instance of the corresponding base class• As illustrated in the book’s example, this can be

useful when using a parser to determine construction parameters

Page 107: Chapter 15 Builder Summary prepared by Kirk Scott 1.

107

• Not only does a builder accomplish the offloading of construction.

• Although it can be thought of as step-by-step, gradual construction, in reality, it’s delayed construction.

• The construction parameters can be tested, and only if they are OK does the build() method ultimately construct and return a reference to an object

Page 108: Chapter 15 Builder Summary prepared by Kirk Scott 1.

108

The End