Create new object with Builder pattern with "old" object reference

22,303

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

  1. Either pass the "old" object in the Builder constructor
  2. 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
Share:
22,303
sk2212
Author by

sk2212

Updated on April 26, 2020

Comments

  • sk2212
    sk2212 about 4 years

    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?

    • Sotirios Delimanolis
      Sotirios Delimanolis about 11 years
      Which old object reference are you talking about here? Add a parameter to the build() method. This ends up having the same effect as a copy constructor.
    • sk2212
      sk2212 about 11 years
      old object reference means a "old" object of MsProjectTaskData. I want to clone this object with the new value which is set within withTransfered(true) method.
    • Fildor
      Fildor about 11 years
      In this special case a simple setTransfered() would do the job. If your goal is to get familiar with builder Pattern and its implementation, I guess you'll have to go and find a better example. What you are doing here looks more like Prototyping to me.
    • sk2212
      sk2212 about 11 years
      @Fildor Yes, but I want to keep the object immutable.
    • Fildor
      Fildor about 11 years
      I see. Well, you could give the Builder a "from" Method that takes a MsProjectTaskData as "Template" and then only change the Fields you want for the new instance. Oh, yeah or CTOR-arg as Eugene sais ..
  • sk2212
    sk2212 about 11 years
    Can you please provide some code? I did not get it to work :(.
  • sk2212
    sk2212 about 11 years
    thanks, that works! Well you say that maybe the use of Builder pattern is not really useful here. Currently I try to change my mutable objects of my current project to immutable ones. This is not so easy if I need to change a property of such an object and put this one back to a container arraylist.
  • Admin
    Admin over 7 years
    @Eugene I have exactly similar problem on cloning the builder pattern to make a new builder here. I wanted to see if you can help me out.