Download StudentBuilderDemo.java
1: // Student.java - A demo of using optional constructor arguments by 2: // using the "constructor builder pattern". Student objects represent 3: // students enrolled in a college course and have many attributes. 4: // With more than a few, multiple constructors become hard to use well. 5: // The alternative of the "JavaBean" pattern (of providing "getters" and 6: // "setters" for each attribute) allows for inconsistant states and 7: // prevents immutable objects (desirable when possible). 8: // 9: // The builder "helper" class is nested within the Student class, 10: // to allow it access to the single private Student constructor. The 11: // only way to construct a Student is to create a Builder, set the 12: // optional values, then call Builder.build method. 13: // 14: // Also notice how each method of the builder returns the (modified) 15: // builder. This allows the method calls to be "chained", simulating 16: // named optional parameters. 17: // (Validity checking of arguments and other details omitted for clarity.) 18: // 19: // Written 5/2008 by Wayne Pollock, Tampa Florida USA. All Rights Reserved. 20: // Updated 3/2021: Replaced mutable Date with immutable LocalDate. 21: 22: import java.time.*; 23: 24: class Student 25: { 26: private static int nextStudentID; 27: 28: static { 29: // Typically fetched from a DB at application (JVM) startup: 30: // nextStudentID = ...; 31: nextStudentID = 1; // For demo purposes 32: } 33: 34: // Add a shutdown hook to save the current value of nextStudentID 35: // to the DB when the application (the JVM) exits: 36: // ... 37: 38: private int studentID; 39: private String lastName; 40: private String firstName; 41: private String address; 42: private String homePhone; 43: private int level; // 1 = freshman, ... 44: private LocalDate enrolled; 45: // ... 46: 47: // Single private Student constructor: 48: private Student ( Builder builder ) 49: { 50: studentID = builder.studentID; 51: lastName = builder.lastName; 52: firstName = builder.firstName; 53: address = builder.address; 54: homePhone = builder.homePhone; 55: level = builder.level; 56: enrolled = builder.enrolled; 57: } 58: 59: // Nested class: 60: public static class Builder 61: { 62: // Required Parameters: 63: private final int studentID; 64: private String lastName; 65: 66: // Optional Parameters (initialized to default values): 67: private String firstName = ""; 68: private String address = "unknown"; 69: private String homePhone = "unknown"; 70: private int level = 1; 71: private LocalDate enrolled = LocalDate.now(); 72: 73: // Public builder constructor, with required parameter: 74: public Builder ( String lastName ) 75: { this.studentID = nextStudentID; 76: ++nextStudentID; 77: this.lastName = lastName; 78: } 79: 80: // Public builder methods for optional parameters (simulates 81: // named parameters): 82: public Builder firstName ( String arg ) 83: { firstName = arg; return this; } 84: public Builder address ( String arg ) 85: { address = arg; return this; } 86: public Builder homePhone ( String arg ) 87: { homePhone = arg; return this; } 88: public Builder level ( int arg ) 89: { level = arg; return this; } 90: public Builder enrolled ( LocalDate arg ) 91: { enrolled = arg; return this; } 92: 93: // Public build method, called after setting the optional fields: 94: public Student build () { return new Student( this ); } 95: } 96: 97: // public Student methods go here: 98: // ... 99: 100: // Display all fields & values (for demo purposes): 101: public String toString () { 102: return "studentID: " + studentID + 103: "\nlastName: " + lastName + 104: "\nfirstName: " + firstName + 105: "\naddress: " + address + 106: "\nhomePhone: " + homePhone + 107: "\nlevel: " + level + 108: "\nenrolled: " + enrolled; 109: } 110: } 111: 112: // Sample use (all the above complexity is so we can do this): 113: public class StudentBuilderDemo 114: { 115: public static void main ( String [] args ) { 116: Student s = new Student.Builder("Piffl").firstName("Hymie"). 117: level(4).build(); 118: // ... 119: System.out.println( s ); // For demo purposes 120: } 121: }