4

I'm having a class in which many parameters are being added as per new api integration.

For example, earlier I had a class with 4 parameters:

Integer a;
String b;
Map<String, String> c;
List<Integer> e.

So the constructor was:

public SampleClass(Integer a, 
                   String b, 
                   Map<String, String> c,      
                   List<Integer> e) 
{
    this.a = a;
    this.b = b;
    this.c = c;
    this.e = e;
}

Several teams have integrated with my API using this constructor in their code. After sometime, there was a new parameter added to this class. i.e.

Double d;

So I added a new constructor:

public SampleClass(Integer a,
                   String b,
                   Map<String, String> c,
                   List<Integer> e,
                   Double d)
{
    this.a = a;
    this.b = b;
    this.c = c;
    this.e = e;
    this.d = d;
}

And I marked the previous constructor as deprecated. I did not remove the previous constructor because if removed, the client's code would break.

As the new parameters are getting added, I now have constructors with 5 parameters.

Is there a best practice on how the constructors should be deprecated/removed, so that this type of scenario does not occur?

Laurel
  • 5,965
  • 14
  • 31
  • 57
  • Not sure if this is a good idea but you can try usign [Lombok](https://projectlombok.org/features/Builder.html) builder pattern. The only problem (by which I wonder if this is an answer for you) is that Lombok relies that instances are created in this fashion: `Type.builder.param1(valueParam1).others(valueOthers).(...) ... (...).build`, which is something you don't have available for previous clients. Yet if you negotiate with them, wouldn't they be able to do that? I mean Lombok gives you a self managed constructor which is independent of the order of params and independent of the number. – Joao Esperancinha May 16 '16 at 09:08
  • 1
    use `builder Pattern` and in current class use `overloading` for constracturs – Hosseini May 16 '16 at 09:08
  • Possible duplicate of [best practice for passing many arguments to method?](http://stackoverflow.com/questions/2432443/best-practice-for-passing-many-arguments-to-method) – Joe May 16 '16 at 09:09
  • That depends on what the parameters mean. If it is not essential, then you could just keep the old constructor with the old functionality. – Nico Schertler May 16 '16 at 09:11
  • 1
    I think **Builder pattern** should be used. – Necromancer May 16 '16 at 09:26
  • 1
    The most important thing is to have a clear and documented API evolution strategy. So whatever way you choose, you need to be consistent in following it, and you need to document it. – biziclop May 16 '16 at 09:38
  • Yes, builder pattern can be used. However, if the code changes for design pattern are done, I think there will be change in the API. API change is not to be done. Please correct me if I'm going wrong. – SIDDHARTH J MEHTA May 16 '16 at 10:29

3 Answers3

4

Change old constructor from:

public SampleClass(Integer a, 
                   String b, 
                   Map<String, String> c,      
                   List<Integer> e) 
{
    this.a = a;
    this.b = b;
    this.c = c;
    this.e = e;
}

to

public SampleClass(Integer a, 
                   String b, 
                   Map<String, String> c,      
                   List<Integer> e) 
{
    //Zero is passed as a default value, but you can pass anything you want
    this(a,b,c,e,0);
}

This way it will call the new one under the hood.

Still, you did not provide enough info on to which extent the old one should be supported. If it shouldn't at all, you should remove it from the code. This way you will force the users of the API to analyse what changed and wire the new constructor in.

If you do not do this, they WILL keep using the old one, because programmers are lazy :-)

Kelevandos
  • 7,024
  • 2
  • 29
  • 46
  • 1
    It's got nothing to do with laziness. When you publish an API, you make a promise. It's your responsibility to deliver on that promise. – biziclop May 16 '16 at 09:39
  • Yeah, but if the API has to change and does change, the programmers should be responsible and analyse what changed when updating to new version. In reality, if the code compiles and tests pass, most of us will simply assume that nothing changed. And @Deprecated does little to combat that :-D So if the change is for some reason crucial, removing methods from the API is a good way to signify that the user should analyse what changed and why. And if they do not want to, because they trust the API as-is, they can always refrain from updating, at the price of new features, changes etc. C'est la vie – Kelevandos May 16 '16 at 09:43
  • 1
    You only expect mandatory API changes on major version changes, that's the convention. As I said in another comment, what is important is that you have a very clear policy on how to handle instances like this. – biziclop May 16 '16 at 09:56
0

It would be beneficial to follow the Open/closed principle. The class you wrote initially should not be modified when new features are needed but rather another class should be derived from it to extend its functionality.

iluwatar
  • 1,778
  • 1
  • 12
  • 22
  • but then as new parameters are getting added gradually, won't new classes be getting created. Would'nt it be difficult to manage all these classes? – SIDDHARTH J MEHTA May 18 '16 at 06:50
-2

Why don't you make use of variable argument constructor.This way you can pass as many arguments to the constructor as you wish.

For example :

public double average( double... numbers ){

       double total = 0.0; // initialize total

      // calculate total using the enhanced for statement
      for ( double d : numbers )              
         total += d;                          

      return total / numbers.length;
   } // end method average
rootExplorr
  • 575
  • 3
  • 17