I am playing around with the Builder pattern and get stuck how to add a new "property" to a new-created object:
public class MsProjectTaskData {
private boolean isAlreadyTransfered;
private String req;
public static class Builder {
private boolean isAlreadyTransfered = false;
public Builder withTransfered(boolean val) {
isAlreadyTransfered = val;
return this;
}
public MsProjectTaskData build() {
return new MsProjectTaskData(this);
}
}
private MsProjectTaskData(Builder builder) {
isAlreadyTransfered = builder.isAlreadyTransfered;
}
public MsProjectTaskData(String req) {
this.req = req;
}
}
I can create a new object with Builder like this:
MsProjectTaskData data = new MsProjectTaskData.Builder().withTransfered(true).build();
But with this approach the req string from a new-created object is lost (of course).
Is there a possibility to create a new object with the new set isAlreadyTransfered variable and with the "old" req string from a "old" object?
Maybe I have to pass the old object reference to the Builder but I do not know how to do this. Maybe the use of Builder pattern is not really usefull for this approach?
EDIT: (After comment from Eugene)
Think, I got it:
public static class Builder {
private boolean isAlreadyTransfered = false;
private MsProjectTaskData data;
public Builder(MsProjectTaskData data) {
this.data = data;
}
public Builder withTransfered(boolean val) {
isAlreadyTransfered = val;
data.setAlreadyTransfered(isAlreadyTransfered);
return this;
}
public MsProjectTaskData build() {
return data;
}
}
Seems to work or is something wrong with the code above? Can I use this approach without consideration?
Make the Builder constructor take as an argument the "old" object and set whatever you want from it to the new one.
Edit
You need to read a bit more about the builder pattern to get a better grasp at what it is and if you really need it.
The general idea is that Builder pattern is used when you have optional elements. Effective Java Item 2 is your best friend here.
For your class, if you want to build one object from another and use a Builder pattern at the same time, you
Either pass the "old" object in the Builder constructor
Create a method from or fromOld, etc.
So how does that looks like? I am going to provide only the first one you can figure out the second on your own.
class MsProjectTaskData {
private final String firstname;
private final String lastname;
private final int age;
private MsProjectTaskData(Builder builder){
this.firstname = builder.firstname;
this.lastname = builder.lastname;
this.age = builder.age;
}
public static final class Builder{
//fields that are REQUIRED must be private final
private final String firstname;
private final String lastname;
//fields that are optional are not final
private int age;
public Builder(String firstname, String lastname){
this.firstname = firstname;
this.lastname = lastname;
}
public Builder(MsProjectTaskData data){
this.firstname = data.firstname;
this.lastname = data.lastname;
}
public Builder age(int val){
this.age = val; return this;
}
public MsProjectTaskData build(){
return new MsProjectTaskData(this);
}
}
public String getFirstname() {
return firstname;
}
public String getLastname() {
return lastname;
}
public int getAge() {
return age;
}
}
And how you will create one object from another:
MsProjectTaskData.Builder builder = new MsProjectTaskData.Builder("Bob", "Smith");
MsProjectTaskData oldObj = builder.age(23).build();
MsProjectTaskData.Builder newBuilder = new MsProjectTaskData.Builder(oldObj);
MsProjectTaskData newObj = newBuilder.age(57).build();
System.out.println(newObj.getFirstname() + " " + newObj.getLastname() + " " + newObj.getAge()); // Bob Smith 57
Related
i'm writing a function to create xls sheets from JFXTableView.
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sheet = wb.createSheet("user details");
XSSFRow header = sheet.createRow(0);
String arrayOfHeaders [] = {"Sr. No.","Name of the Member", "Customized workout card status","Contact No.","Current programme taken","Current package taken",
"Purpose of taking customized workout card", "body type identified"," Current Body weight","Current height","payment amount",
"Mode of payment"};
for(int i=0; i<arrayOfHeaders.length; i++){
header.createCell(i).setCellValue(arrayOfHeaders[i]);
}
int index=1;
for(Member item: tableView.getItems()){
XSSFRow row = sheet.createRow(index);
int cellIndex=0;
for (Method m : item.getClass().getMethods()) {
// The getter should start with "get"
// I ignore getClass() method because it never returns null
if (m.getName().startsWith("get") && !m.getName().equals("getClass")) {
row.createCell(cellIndex).setCellValue((String) m.invoke(item));
}
cellIndex++;
}
index++;
}
With the above code, i'm able to retrieve values from the table through the getters, but the problems is item.getClass().getMethods() returns getters in a random order and that is not acceptable as i want the values according to the headers as defined.
I have many such tables, each with their own Class and getters, and writing different functions for each one of them seems too lengthy. So, what i'm planning to do is write a function where i could pass on the getters of each different table object in an array, so it could loop through all the getters of the particular tableView object. Something like this:
createSheets(arrayOfHeaders, tableView.getItems(), arrayOfGetters);
The example of one such Member Class being used by my current tableView is:
public static class Member{
private final SimpleStringProperty name;
private final SimpleStringProperty status;
private final SimpleStringProperty contact;
private final SimpleStringProperty programme;
private final SimpleStringProperty packages;
private final SimpleStringProperty purpose;
private final SimpleStringProperty bodyType;
private final SimpleStringProperty weight;
private final SimpleStringProperty height;
private final SimpleIntegerProperty paymentAmount;
private final SimpleStringProperty paymentMode;
public Member (String name, String status, String contact, String programme, String packages, String purpose,
String bodyType, String weight, String height, int paymentAmount, String paymentMode){
this.name = new SimpleStringProperty(name);
this.status = new SimpleStringProperty(status);
this.contact = new SimpleStringProperty(contact);
this.programme = new SimpleStringProperty(programme);
this.packages = new SimpleStringProperty(packages);
this.purpose = new SimpleStringProperty(purpose);
this.bodyType = new SimpleStringProperty(bodyType);
this.weight = new SimpleStringProperty(weight);
this.height = new SimpleStringProperty(height);
this.paymentAmount = new SimpleIntegerProperty(paymentAmount);
this.paymentMode = new SimpleStringProperty(paymentMode);
}
public String getName() {
return name.get();
}
public String getStatus() {
return status.get();
}
public String getContact() {
return contact.get();
}
public String getProgramme() {
return programme.get();
}
public String getPackages() {
return packages.get();
}
public String getPurpose() {
return purpose.get();
}
public String getBodyType() {
return bodyType.get();
}
public String getWeight() {
return weight.get();
}
public String getHeight() {
return height.get();
}
public int getPaymentAmount() {
return paymentAmount.get();
}
public String getPaymentMode() {
return paymentMode.get();
}
}
This question already has answers here:
When would you use the Builder Pattern? [closed]
(13 answers)
Closed 7 years ago.
Recently I saw some of the developers coding their VOs with nested builder class like
public class User {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public static class UserBuilder {
private String firstName;
private String lastName;
public User build() {
User user = new User();
user.firstName = firstName;
user.lastName = lastName;
return user;
}
public UserBuilder withFirstName(String firstName) {
this.firstName = firstName;
return this;
}
public UserBuilder withLastName(String lastName) {
this.firstName = firstName;
return this;
}
}
}
Now, they claim that this makes code more readable. My point is, this has following disadvantages:
I can't simply add fields and expect my IDE to complete code for me, as now I need to update this inner class too.
Simple POJOs are carrying code which is not relevant for VO.
I am looking for any advice if I am missing something here. Feel free to add your thoughts about the same.
Sample code after this modification looks like,
User user = new User.UserBuilder()
.withFirstName("Name")
.withLastName("surName")
.build();
Here is an article from Joshua Bloch. He explains very well why, when and how to use a builder : http://www.informit.com/articles/article.aspx?p=1216151&seqNum=2
It is one of items in his book called Effective Java. I strongly advise you to read this book if you have a little experience with Java.
Main point :
When you you get a class with a lot of attribute there is several ways create an object and init it.
If you set one by one every attributes it can be wordy and your object could be altered after its creation. With this method it is impossible to make your class immutable and you cannot be sure that your object is in consistent state.
Exemple from the article :
public class NutritionFacts {
// Parameters initialized to default values (if any)
private int servingSize = -1; // Required; no default value
private int servings = -1; // " " " "
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0;
public NutritionFacts() { }
// Setters
public void setServingSize(int val) { servingSize = val; }
public void setServings(int val) { servings = val; }
public void setCalories(int val) { calories = val; }
public void setFat(int val) { fat = val; }
public void setSodium(int val) { sodium = val; }
public void setCarbohydrate(int val) { carbohydrate = val; }
}
You can use a telescoping constructor. It can make your object immutable. However if you get many attributes it can be hard to write and read your code. More over when you just want create with one setted attribute, and unfortunately this one is the last parameter of the constructor, you have to set all parameter anyway.
Exemple from the article :
public class NutritionFacts {
private final int servingSize; // (mL) required
private final int servings; // (per container) required
private final int calories; // optional
private final int fat; // (g) optional
private final int sodium; // (mg) optional
private final int carbohydrate; // (g) optional
public NutritionFacts(int servingSize, int servings) {
this(servingSize, servings, 0);
}
public NutritionFacts(int servingSize, int servings,
int calories) {
this(servingSize, servings, calories, 0);
}
public NutritionFacts(int servingSize, int servings,
int calories, int fat) {
this(servingSize, servings, calories, fat, 0);
}
public NutritionFacts(int servingSize, int servings,
int calories, int fat, int sodium) {
this(servingSize, servings, calories, fat, sodium, 0);
}
public NutritionFacts(int servingSize, int servings,
int calories, int fat, int sodium, int carbohydrate) {
this.servingSize = servingSize;
this.servings = servings;
this.calories = calories;
this.fat = fat;
this.sodium = sodium;
this.carbohydrate = carbohydrate;
}
}
The builder allows to make your code more readable and easy to write. It also allows you to be able to make your class immutable.
Exemple from the article :
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public static class Builder {
// Required parameters
private final int servingSize;
private final int servings;
// Optional parameters - initialized to default values
private int calories = 0;
private int fat = 0;
private int carbohydrate = 0;
private int sodium = 0;
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val)
{ calories = val; return this; }
public Builder fat(int val)
{ fat = val; return this; }
public Builder carbohydrate(int val)
{ carbohydrate = val; return this; }
public Builder sodium(int val)
{ sodium = val; return this; }
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
}
In your example I'm not sure that it is very useful to do a builder for a class with only two attributes.
I hope this will help you.
IMHO in the given example you gain no value by using Builder pattern. You can create User object without the Builder (because of all the setters). The only thing that Builder gives you in this particular case is Fluent Interface.
You should use Builder Pattern when there are various combinations of creating a valid object. Thanks to this you won't have to implement many constructors or factory methods.
Builder is also helpful when creating a valid object requires many parameters.
Builder should be responsible for build only a valid objects. In your case, if User needs to have first and last name Builder shouldn't allow to create the instance of User that doesn't have those attributes set.
Start with small immutable objects
If all your properties are required then you should use just constructor. By doing this you might create nice small immutable object.
Builders are helpful when you have multiple optional fields
If there are multiple optional fields and different ways to create an object you'd need multiple constructors.
public User (int requiredParameter) { ... }
public User (int reqiredParameter, int optionalParameter) { ... }
public User (int reqiredParameter, int optionalParameter, String optionalParameter2) { ... }
public User (int reqiredParameter, String optionalParameter2) { ... }
It creates messy code. It is hard to determine which constructor you should use.
In this case you could use nested builder to have intuitive way of creating your object.
I'm facing this task:
I have class A and class B. These two classes are different but almost the same.
I need to somehow merge them into 1 Single array of objects so I will be able to use them later in a list that combines both classes.
Class A:
public class Followers {
private String request_id;
private String number_sender;
private String state;
public String getRequest_id() {
return request_id;
}
public String getNumber_sender() {
return number_sender;
}
public String getState() {
return state;
}
}
Class B:
public class Following {
private String name;
private String state;
private String request_id;
public String getRequest_id() {
return request_id;
}
public String getName() {
return name;
}
public String getState() {
return state;
}
}
I've tried doing this next move:
Object[] obj1 = (Object[]) followers;
Object[] obj2 = (Object[]) followings;
Object[] completeArray = ArrayUtils.addAll(obj1, obj2);
Where followers and followings are both arrays of the corresponding classes. Then in my list adapter I use:
if (values[currentItem] instanceof Followers) { BLA BLA BLA}
else if (values[currentItem] instanceof Following) { BLA BLA BLA}
But I get this exception:
Caused by: java.lang.ArrayStoreException: source[0] of type json.objects.Following cannot be stored in destination array of type json.objects.Followers[]
What will be the best way to merge two arrays of different objects into one array?
Will just implementing the same interface between them do the job and then they will basically be in an array of the interface type?
what other ways do you recommend?
Try this
Object[] completeArray = new Object[0];
completeArray = ArrayUtils.addAll(completeArray, obj1);
completeArray = ArrayUtils.addAll(completeArray, obj2);
If you make both classes implement a common interface you can manipulate arrays/lists of them as if they contains instances of the interface.
public interface Follow {
public String getRequest_id();
public String getState();
}
public class Follower implements Follow {
private String request_id;
private String number_sender;
private String state;
public String getRequest_id() {
return request_id;
}
public String getNumber_sender() {
return number_sender;
}
public String getState() {
return state;
}
}
public class Following implements Follow {
private String name;
private String state;
private String request_id;
public String getRequest_id() {
return request_id;
}
public String getName() {
return name;
}
public String getState() {
return state;
}
}
public void test() {
List<Follow> all = new ArrayList<>();
all.add(new Following());
all.add(new Follower());
for ( Follow f : all ) {
String id = f.getRequest_id();
String state = f.getState();
}
}
Alternatively you could put them in a hierarchy:
public class Entity {
private String request_id;
private String state;
public String getRequest_id() {
return request_id;
}
public String getState() {
return state;
}
}
public class Follower extends Entity {
private String number_sender;
public String getNumber_sender() {
return number_sender;
}
}
public class Following extends Entity {
private String name;
public String getName() {
return name;
}
}
public void test() {
List<Entity> all = new ArrayList<>();
all.add(new Following());
all.add(new Follower());
for ( Entity f : all ) {
String id = f.getRequest_id();
String state = f.getState();
}
}
Or you could make the extra fields into attributes.
enum Attribute {
Follows,
Followed;
}
public static class Entity {
private String request_id;
private String state;
EnumMap<Attribute, String> attributes = new EnumMap<>(Attribute.class);
public String getRequest_id() {
return request_id;
}
public String getState() {
return state;
}
// Factory to make entities.
static Entity make(Attribute attribute, String value) {
Entity e = new Entity();
e.attributes.put(attribute, value);
return e;
}
}
public void test() {
List<Entity> all = new ArrayList<>();
all.add(Entity.make(Attribute.Follows, "Fred"));
all.add(Entity.make(Attribute.Followed, "Gill"));
for (Entity f : all) {
String id = f.getRequest_id();
String state = f.getState();
}
}
There are an infinite number of possibilities.
USE concat
var combined= obj1.concat(obj2); // Merges both arrays
Try this.
private Object[] appendObj(Object[] obj, Object newObj) {
ArrayList<Object> temp = new ArrayList<Object>(Arrays.asList(obj));
temp.add(newObj);
return temp.toArray();
}
I'm a web developer dabbling in Java (again) and I'm having trouble with something.
Basically, I have a superclass Employee with two subclasses that extend it called Management and Programmer. The Employee class contains an array employees that is basically an array of Employee objects.
Here's the important snippets of two of the classes (Employee and Management) and the final main method. I'll explain the output at the bottom.
public class **Employee** {
private static String firstName;
protected static int MAXEMPLOYEES = 5;
protected Employee[] employees = new Employee[MAXEMPLOYEES];
protected int totEmployees = 0;
public Employee(String first) {
setFirstName(first);
}
public void setFirstName(String str){
firstName = str;
}
public String getFirstName(){
return firstName;
}
public boolean addEmployee(String fname) {
boolean added = false;
if (totEmployees < MAXEMPLOYEES) {
Employee empl = new Employee(fname);
employees[totEmployees] = empl;
added = true;
totEmployees++;
}
return added;
}
}
public class **Management** extends **Employee** {
private String title = "Project Manager";
public Management(String fname, String t){
super(fname);
title = t;
}
public boolean addManagement(String fname, String t){
boolean added = false;
if (totEmployees < MAXEMPLOYEES) {
employees[totEmployees] = new Management(fname, t);
added = true;
totEmployees++;
}
return added;
}
}
-------------------------------------
package employee;
public class EmployeeApplication {
public static void main(String[] args) {
Employee[] empl = new Employee[3];
empl[0] = new Employee("Kyle");
empl[1] = new Management("Sheree", "Director");
System.out.println(empl[0].getFirstName());
}
}
Now, I expect the system to print out "Kyle", but it prints out "Sheree". Any ideas???
private static String firstName;
You made firstName static, which means all instances share the same name. You'll need to remove the static modifier in order for different Employees to have different names. You'll also need to change the private access modifier to protected in order for the field to be inherited by subclasses.
private String firstName;
remove static;
Kyle was overridden by Sheree, that is why you are getting that output
I have an enumeration called PaymentFrequency:
public enum PaymentFrequency {
D("Daily"),
W("Weekly"),
M("Monthly"),
Y("Yearly");
private final String description;
PaymentFrequency(final String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
And now if I do this in my bean:
private PaymentFrequency[] paymentPeriods = PaymentFrequency.values();
public PaymentFrequency[] getPaymentPeriods() {
return paymentPeriods;
}
public void setPaymentPeriods(PaymentFrequency[] paymentPeriods) {
this.paymentPeriods = paymentPeriods;
}
I will get all the values from my enumeration. How can I get only the values W and M ?
Well, you could do
private PaymentFrequency[] paymentPeriods =
new PaymentFrequency[] {PaymentFrequency.W, PaymentFrequency.M};
You can add an array
static final PaymentFrequency[] WM = { W, M };
private PaymentFrequency[] paymentPeriods = new PaymentFrequency[] {PaymentFrequency.W, PaymentFrequency.M};
I'm not sure if this is your question...