Java constructor with large arguments or Java bean getter/setter approach

后端 未结 18 2200
清歌不尽
清歌不尽 2020-12-12 21:29

I can\'t decide which approach is better for creating objects with a large number of fields (10+) (all mandatory) the constructor approach of the getter/setter. Constructor

18条回答
  •  没有蜡笔的小新
    2020-12-12 22:26

    I would recommend you consider the builder pattern in such a case. You are guaranteed to get a valid object, without just having a huge list of parameters.

    The OP was update to reject the builder pattern, but it seems to be based on a misunderstanding. The fact that the Builder pattern exists does not remove the enforcement of all the parameters.

    Consider the following object:

     public class SomeImmutableObject {
          private String requiredParam1;
          private String requiredParam2;
          //etc.
    
          private SomeImmutableObject() { //cannot be instantiated outside the class }
    
          public static class Builder {
              private SomeImmutableObject instance;
              public Builder() { instance = new SomeImmutableObject();
              public Builder setParameter1(String value) {
                   instance.requiredParam1 = value;
                   return this;
              }
              //etc for each parameter.
    
              public SomeImmutableObject build() {
                 if (instance.requiredParam1 == null || instance.requiredParam2 == null /*etc*/)
                    throw new IllegalStateException("All required parameters were not supplied.");
                 return instance;
              }
          } 
     }
    

    Note that you can accomplish basically the same thing by making the fields package private and putting the builder in the same package.

    And if for some reason you can't do that, you can still have the constructor with the 10 parameters, and then have the Builder be the only thing that calls that constructor, so that it is an easier API to use.

    So for all stated requirements, the Builder pattern works just fine. The fact that all 10 parameters are required does not disqualify the Builder pattern at all. If there is some other need that the pattern doesn't satisfy, please elaborate.

    Edit: The OP added a comment (quite a while ago, but I just got an upvote on this question so I only saw it now) with an interesting question: How do you validate a primitive at a later point in time?

    There are a few ways around that problem, including a guarding boolean, but my preferred way would be to use a Double object like so:

         private Double doubleForPrimitive;
    
         public Builder setDouble(double d) {
             doubleForPrimitive = d;
         }
    
         public SomeImmutableObject build() {
             if(doubleForPrimitive != null) {
                   instance.doubleParam = doubleForPrimitive;
             } else {
                    throw new IllegalArgumentExcepion("The parameter double was not provided");
             }
             //etc.
         }
    

    It should be noted that if you need true thread-safe immutability having all of the fields of the immutable object as final, this requires more boilerplate (storing the variables inside the builder and passing them to a private constructor of the immutable object), but the approach is still clean from the point of view of the client code.

提交回复
热议问题