I have created a Person, class and a Professor class that both use the Builder Pattern to create objects. The Professor class takes a Person object as an argument in its constructor. I am trying to use both classes together, but when I attempt to print out a professor, get the following output: null null (instead of Bob Smith).
Here's what I tried so far:
Person:
public class Person {
private String firstname;
private String lastname;
private int age;
private String phoneNumber;
private String emailAddress;
private char gender;
public Person(){}
// builder pattern chosen due to number of instance fields
public static class PersonBuilder {
// required parameters
private final String firstname;
private final String lastname;
// optional parameters
private int age;
private String phoneNumber;
private String emailAddress;
private char gender;
public PersonBuilder(String firstname, String lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
public PersonBuilder age(int age) {
this.age = age;
return this;
}
public PersonBuilder phoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
return this;
}
public PersonBuilder emailAddress(String emailAddress) {
this.emailAddress = emailAddress;
return this;
}
public PersonBuilder gender(char gender) {
this.gender = gender;
return this;
}
public Person build() {
return new Person(this);
}
}
// person constructor
private Person(PersonBuilder builder) {
this.firstname = builder.firstname;
this.lastname = builder.lastname;
this.age = builder.age;
this.phoneNumber = builder.phoneNumber;
this.emailAddress = builder.emailAddress;
this.gender = builder.gender;
}
#Override
public String toString() {
return this.firstname + " " + this.lastname;
}
}
Here's the Professor class:
package com.example.hardcodedloginform;
import java.util.List;
public class Professor extends Person{
private Person professor;
private double salary;
private String courseTaught;
private List<Student> students;
private int professorID;
public static class ProfessorBuilder {
// required fields
private Person professor;
private int professorID;
// optional fields
private double salary;
private String courseTaught;
private List<Student> students;
public ProfessorBuilder(Person professor, int professorID) {
this.professor = professor;
this.professorID = professorID;
}
public ProfessorBuilder salary(double salary) {
this.salary = salary;
return this;
}
public ProfessorBuilder courseTaught(String courseTaught) {
this.courseTaught = courseTaught;
return this;
}
public ProfessorBuilder students(List<Student> students) {
this.students = students;
return this;
}
public Professor build() {
return new Professor(this);
}
}
private Professor(ProfessorBuilder builder) {
this.salary = builder.salary;
this.courseTaught = builder.courseTaught;
this.students = builder.students;
}
#Override
public String toString() {
return "" + super.toString();
}
}
And here is the Main class where I try to print out a professor object:
public class Main {
public static void main(String[] args) {
Person profBobs = new Person.PersonBuilder("Bob", "Smith")
.age(35)
.emailAddress("bob.smith#SNHU.edu")
.gender('M')
.phoneNumber("818-987-6574")
.build();
Professor profBob = new Professor.ProfessorBuilder(profBobs, 12345)
.courseTaught("MAT101")
.salary(15230.01)
.build();
System.out.println(profBob);
}
}
I would like the printout in the console to be "Bob Smith", but what I am seeing is: null null. I checked and found that the Person object profBobs is, in fact, created properly and does print out the name "Bob Smith" when I attempt to print it the same way. I don't know why my Professor prints: null null.
Your Professor constructor fails to initialise any member fields of its base class.
There are multiple ways to solve this. One solution has ProfessorBuilder extend PersonBuilder:
public class Professor extends Person {
// Remove the `person` field! A professor *is-a* person, it does not *contain* it.
private double salary;
private String courseTaught;
private List<Student> students;
private int professorID;
public static class ProfessorBuilder extends Person.PersonBuilder {
// required fields
private int professorID;
// optional fields
private double salary;
private String courseTaught;
private List<Student> students;
public ProfessorBuilder(Person professor, int professorID) {
super(professor);
this.professorID = professorID;
}
// …
}
private Professor(ProfessorBuilder builder) {
super(builder);
this.salary = builder.salary;
this.courseTaught = builder.courseTaught;
this.students = builder.students;
}
}
For this to work you also need to mark the Person constructor as protected rather than private.
Furthermore, your Professor.toString method implementation made no sense: it essentially just called the base class method, so there’s no need to override it. And prepending the empty string does nothing.
Related
I have a student class with few fields. For some reason, I am not getting "created" object created in Student object. When i send GET call to receive information of all student objects, I see only first 4 parameters. It is missing created field missing. What am I missing?
In Student constructor I have defined "this.created = new Date();" to assign value to created field.
public class Student {
private String firstName;
private String lastName;
private String address;
private String enrolledDepartment;
private Date created;
public Student() {
}
public Student(String firstName, String lastName, String address, String departmentName){
this.firstName = firstName;
this.lastName = lastName;
this.address = address;
this.enrolledDepartment = departmentName;
this.created = new Date();
}
// Getter and setters of all fields
}
Resource class
#Path("/students")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class StudentsResource {
List<Student> students = new ArrayList<>();
private StudentService studentService = new StudentService();
#GET
public List<Student> getProfiles() {
return studentService.getAllStudents();
}
#POST
public Student addProfile(Student profile) {
return studentService.addProfile(profile);
}
}
Service class
public class StudentService {
private List<Student> students = DatabaseClass.getStudents();
public List<Student> getAllStudents() {
return students;
}
public Student addProfile(Student student) {
students.add(student);
return student;
}
}
Database class
public class DatabaseClass {
private static List<Student> students = new ArrayList<>();
private static List<Email> emails = new ArrayList<>();
public static List<Student> getStudents() {
return students;
}
public static List<Email> getEmails() {
return emails;
}
}
I am sending a POST request using following JSON
{
"address": "Boston",
"enrolledDepartment": "health",
"firstName": "abc",
"lastName": "pqr"
}
Add this to the "default constructor":
public Student() {
this.created = new Date();
}
...the constructor, that you assume, is not called, thus created remains null.
or even:
// ...
private Date created = new Date();
public Student() {
}
public Student(String firstName, String lastName, String address, String departmentName){
this.firstName = firstName;
this.lastName = lastName;
this.address = address;
this.enrolledDepartment = departmentName;
//this.created = new Date();
}
(initialize it in the declaration.)
im trying to learn how to use pattern builder. i could get it to work until i tried to use enum.
I tried to change the code couple of times and each time had different error. right now the error is Incompatible types.
Please can you help bringing this code to working state and if you have suggestions to improve the code it would be great.
thanks.
EDIT:
now it seems to be okay, but how do i use it with the builder inside the main?
this was the code i used
main:
Person person3 = new Person.PersonBuilder("Julliete", "Kaplan" )
.status(); // what should i write here to set the status?
person class
public class Person
{
private final String name;
private final String lastname;
private final int age;
//My enum im trying to use
private Status status;
public enum Status
{
SINGLE ("Single"), MARRIED ("Married"), WIDOWER ("Widower");
private String status;
private Status(String status)
{
this.status = status;
}
public String getStatus()
{
return this.status;
}
}
//builder
private Person(PersonBuilder builder) {
this.name = builder.name;
this.lastname = builder.lastname;
this.age = builder.age;
this.status = builder.status;
}
//GETTERS
public String getName() {
return name;
}
public String getLastname() {
return lastname;
}
public int getAge() {
return age;
}
#Override
public String toString() {
return "Person : "+this.name+", "+this.lastname+", "+this.age;
}
//PersonBuilder
public static class PersonBuilder
{
private final String name;
private final String lastname;
private int age;
private Status status;
public PersonBuilder(String name, String lastname) {
this.name = name;
this.lastname = lastname;
}
public PersonBuilder age(int age) {
this.age = age;
return this;
}
public PersonBuilder status(Status status)
{
this.status = status;
return this;
}
public Person build() {
Person person = new Person(this);
return person;
}
}
Don't define another Status enum inside the builder: reuse the one defined in the Person class.
Otherwise, you've got to map from instances of PersonBuilder.Status to instances of Person.Status: they are entirely separate types.
Currently this mapping is trivial: you can use Person.Status.valueOf(personBuilderStatus.name()) - but you have to ensure that you update both at the same time to have identical values (or at least that PersonBuilder.Status maps to a subset of Person.Status), which is an unnecessary maintenance burden going forwards.
Question before editing: How can I delegate the initialization process of too many member variable of class A inside class B and C and still use the value inside class A?
Note: (class B and C is present inside class A)
The main objective is to reduce too many member variables present in class A.
I am following whats it is said in this post [1]: https://stackoverflow.com/a/16994754/2018343
code would be like is
UPDATED:
public class A{ // start of class A
public int a;
int b;
public int c;
int d;
int x;
int g;
B bObject; //instance of class B
C cObject; //instance of class B
A(){ /**Constructor*/
bObject = new B(3,4);
cObject = new C(5,6);
} /*
*There is an error in eclipse after this closing bracket
*"Syntax error on token "}", { expected after this token"
*/
/**
* My end goal: I need to Use the initialized variables after the constructor
*/
public void yui(){
if(true){ // variables a and c
// System.out.println("A is greater");
x=a;
g=c;
}
} /**
* Syntax error on token "}", { expected after this token */
if(x<g){ // variables x and g
System.out.println("A is greater");
}
class B{ //Note: This class is inside class A
B(int val1, int val2){
a=val1;
b=val2;
}
}
class C{ // //Note: This class is inside class A
C(int val3,int val4){
c= val3;
d= val4;
}
}
public static void main(String[] args){
A a = new A();
a.yui();
}
} // end of class A
I am really looking for delegating the initialization process of too many variables to other child class and main thing is use that initialized variable value in the subsequent lines of code in master class.
Seek your help!
You can use the Builder pattern to make the initialization more user friendly.
A nice example that was taken from here:
public class User {
private final String firstName; // required
private final String lastName; // required
private final int age; // optional
private final String phone; // optional
private final String address; // optional
private User(UserBuilder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.age = builder.age;
this.phone = builder.phone;
this.address = builder.address;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
public String getPhone() {
return phone;
}
public String getAddress() {
return address;
}
public static class UserBuilder {
private final String firstName;
private final String lastName;
private int age;
private String phone;
private String address;
public UserBuilder(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
public UserBuilder phone(String phone) {
this.phone = phone;
return this;
}
public UserBuilder address(String address) {
this.address = address;
return this;
}
public User build() {
return new User(this);
}
}
}
and how to use it:
public User getUser() {
return new
User.UserBuilder("Jhon", "Doe")
.age(30)
.phone("1234567")
.address("Fake address 1234")
.build();
}
I have a problem in realisation of Builder pattern.
I have 2 classes:
package course_2;
import java.util.Date;
public class Student {
private static int idStart = 0;
private final int id = idStart++;
private String name;
private String surname;
private String secondName;
private Date birthDate;
private String address;
private String phone;
private int course;
private int group;
public static class Builder {
// Обязательные параметры
private final String name;
private final String surname;
private final Date birthDate;
// Необязательные параметры, инициализация по умолчанию
private String secondName = "";
private String address = "";
private String phone = "";
private int course = 1;
private int group = 1;
public Builder(String name, String surname, Date birthDate) {
this.name = name;
this.surname = surname;
this.birthDate = (Date) birthDate.clone();
}
public Builder SecondName(String secondName) {
this.secondName = secondName;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
public Builder phone(String phone) {
this.phone = phone;
return this;
}
public Builder course(int course) {
this.course = course;
return this;
}
public Builder group(int group) {
this.group = group;
return this;
}
}
private Student(Builder builder) {
this.name = builder.name;
this.surname = builder.surname;
this.secondName = builder.secondName;
this.birthDate = builder.birthDate;
this.address = builder.address;
this.phone = builder.phone;
this.course = builder.course;
this.group = builder.group;
}
}
The problem is when I'm trying to call a Builder from my client code:
Student studentOne = new Student.Builder("Andrue", "Booble", /*Date variable here*/);
I'm getting a compiler problem :
Error:(24, 30) java: incompatible types: course_2.Student.Builder
cannot be converted to course_2.Student
Can somebody help me with understanding, why does this happen and how I can solve it? Thanks!
You need to add the following to your Builder:
public Student build(){
return new Student(this);
}
And call it like this:
Student studentOne = new Student.Builder("Andrue", "Booble", null).build();
new Student.Builder("Andrue", "Booble", /*Date variable here*/); returns you builder object not student.
Your factory is missing method create which invoke Student constructor
it should looks like this
public Student create(){
return new student (this);
}
and be implemented inside Builder class
now if you want to create Student, you call
Student studentOne = new Student.Builder("Andrue", "Booble", /*Date variable here*/).create();
Recently I am doing a coding exercises I need to make my project , and so far I am practicing it with the code below what I want to ask is that, is this a has a relationship? am I doing the right practice? look at my code, sorry for my bad english
public class Personal {
private String firstName;
private String middleInitial;
private String lastName;
private int age;
public Personal(String firstName,String middleInitial , String lastName , int age){
setFirstName(firstName);
setMiddleInitial(middleInitial);
setLastName(lastName);
setAge(age);
}
public void setFirstName(String firstName){
this.firstName = firstName;
}
public String getFirstName(){
return firstName;
}
public void setMiddleInitial(String middleInitial){
this.middleInitial = middleInitial;
}
public String getMiddleInitial(){
return middleInitial;
}
public void setLastName(String lastName){
this.lastName = lastName;
}
public String getLastName(){
return lastName;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
public String toString(){
return String.format("First Name: "+getFirstName()+"\nMiddle Initial: "+getMiddleInitial()+
"\nLast Name: "+getLastName()+"\nAge: "+getAge());
}
}
Contact Class
public class Contact {
private String address;
private String email;
private String contactNumber;
public Contact(String address,String contactNumber, String email){
setAddress(address);
setContactNumber(contactNumber);
setEmail(email);
}
public void setAddress(String address){
this.address = address;
}
public String getAddress(){
return address;
}
public void setEmail(String email){
this.email = email;
}
public String getEmail(){
return email;
}
public void setContactNumber(String contactNumber){
this.contactNumber = contactNumber;
}
public String getContactNumber(){
return contactNumber;
}
public String toString(){
return String.format("Address: "+getAddress()+"\nContact Number: "+getContactNumber()+
"\nEmail Address: "+getEmail());
}
}
Employee Class
public class Employee {
private Personal personal;
private Contact contact;
public Employee(Personal personal, Contact contact){
this.personal = personal;
this.contact = contact;
}
public void setFirstName(String firstName){
this.personal.setFirstName(firstName);
}
public String toString(){
return String.format(personal.toString()+contact.toString());
}
}
And the Test class
public class TestClass {
public static void main(String[] args){
Personal personalHerp = new Personal("John","M","Doe",18);
Contact contactHerp = new Contact("88 Herp Derp St U mad New york","724-15-70","fido.com");
Employee employeeHerp = new Employee(personalHerp,contactHerp);
System.out.println(employeeHerp);
}
}
Well, since Employee doesn't extend Personal it has a Personal and a Contact.
I guess you'd rather like Employee to be a Personal and thus it should look like this:
public class Employee extends Personal {
private Contact contact;
...
}
So to summarize:
is-a means a class/object extends another class or implements an interface, i.e. A is-a B if A extends B or A implements B
has-a means that a class/object has a variable of that type, like Contact contact in your Employee class, which means Employee has-a contact.
Yes, this is a "has-a" relationship (exactly as we discussed in your other question).