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

后端 未结 18 2078
清歌不尽
清歌不尽 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:25

    My first thought is to check whether your encapsulation model is correct. Having 10+ mandatory fields sounds like quite a lot and perhaps it makes more sense to have more finely-grained components in this scenario ?

    Are some of these fields/parameters related ? Can they be combined into objects that make sense (e.g. x-coordinate and y-coordinate combined into a Point object etc.)

    0 讨论(0)
  • 2020-12-12 22:25

    You might consider using a builder pattern, with the builder ensuring that all the fields are at least set to sensible defaults. Refer to the link for implementation, but you would wind up with a call that looks something like:

    Widget widge = new Widget.Builder(). manufacturer("333").serialNumber("54321").build();
    
    0 讨论(0)
  • 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.

    0 讨论(0)
  • 2020-12-12 22:26

    If all parameters are in fact mandatory, then I see no reason why not to use a constructor. However, if that's not the case, then using a builder seems like the best approach.
    Relying only on setters is in my opinion the worst solutions since there's nothing to enforce that all mandatory properties are set. Of course if you're using Spring Framework's bean wiring or other similar solution, then Java beans are perfectly fine as you can check after the initialization that everything has been set.

    0 讨论(0)
  • 2020-12-12 22:27

    Can your fields be combined into an intermediate object? For example, if you are passing in 10 fields that describe a person then create a PersonInfo object to pass that data along. I personally prefer passing in all required fields when instantiating the object. That way you don't end up with a half-baked object that will inevitably be used and abused.

    0 讨论(0)
  • 2020-12-12 22:28

    Ten arguments for a constructor is a lot. I would seriously think about if they are all required and some of them wouldn't make sense to combine into logical objects. If there truly are ten distinct required pieces of data, then the constructor should contain ten fields.

    0 讨论(0)
提交回复
热议问题