Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build semantically immutable entity with many fields

I have entity with 25 fields. It has not any logic, just store values. It's build with abstract builder. I don't want something change this entity after build. I want to make all fields final, but i don't want make 25-params constructor. What pattern should I use in this situation? Now I think about package-local setters, but it's worse, than syntax checking for all values setting in final fields. I can't pack this fields in 2-3 objects

like image 399
mishka Avatar asked Dec 03 '22 21:12

mishka


2 Answers

I see three main options:

  1. Have a private class only the builder knows about, and a public interface with only getters. The builder gives out references using the interface, not the class.

  2. Have two classes, one mutable (which is a bit of a messenger class) and one that's immutable, which accepts the mutable one in its constructor and grabs its fields.

  3. Have the class have reasonable default values for all fields, and then have setters which return a new instance of the class with that field set. The downside here is that to build a 25-field instance, you end up creating ~24 throw-away objects, depending on how many of the reasonable defaults you need to change. ;-)

like image 170
T.J. Crowder Avatar answered Dec 24 '22 20:12

T.J. Crowder


Have the Builder class as a static nested class in your Entity class. Then the Builder class can set the fields directly, and you won't need setter methods or a n-arg constructor in Entity.

public class Entity
{
   // Just one attribute and getter here; could be 25.
   private int data;

   public int getData() { return data; }

   public static class Builder
   {
      // Just one attribute and getter here; could be 25.
      private int theData;

      public Entity build()
      {
         Entity entity = new Entity();

         // Set private field(s) here.
         entity.data = theData;

         return entity;
      }

      public Builder setData(int someData)
      {
         theData = someData;
         return this;
      }
   }
}

Usage:

Entity entity = new Entity.Builder().setData(42).build();
like image 40
rgettman Avatar answered Dec 24 '22 20:12

rgettman