AnnanFay
AnnanFay

Reputation: 9759

Best practices regarding allowing many different types to constructors?

I have a class called RawReader that reads the bytes of some resource, parses them, then writes files to an output directory.

It makes sense to allow different types to be passed in as the source and destination to the constructor.

However if I overload the constructor that leaves me with 8 different versions. If I wanted to add a third optional argument for example chunkSize I'd have 16 constructors!

On the other hand I could just have two constructors accepting (Object, Object) and (Object, Object, int). The argument types could be detected and an IllegalArgumentExceptions thrown if they aren't correct.

How are situations like this normally handled in Java?

Upvotes: 3

Views: 235

Answers (4)

user207421
user207421

Reputation: 310980

It makes sense to allow different types to be passed in as the source and destination to the constructor.

Up to a point. However it doesn't make much sense to provide conversions that the caller could just as easily provide himself, especially if it's going to lead to as many as eight constructors. So:

(a) You don't need both String and File. Decide on one, and stick to it. I would use File. That already divides the number of constructors by four.

(b) You don't really need both URL and InputStream either, although there are precedents. Getting rid of 'URL' would divide the number by two.

Upvotes: 0

Bohemian
Bohemian

Reputation: 425198

If you find you have constructors with the same signature, you can use factory methods with different names:

public class Foo {

    public static Foo createForDir(String dir) {
        // create a Foo as you like and return it
    }

    public static Foo createForUrl(String url) {
        // create a Foo as you like and return it
    }
}

Upvotes: 0

Tomasz Nurkiewicz
Tomasz Nurkiewicz

Reputation: 340883

First of all an idea with (Object, Object, int) is terrible, don't go that way! You loose strong-typing, IDE assistance and API clarity.

On your place I would restrict the constructor to most obvious/low-level input you can take and provide a builder/factory methods:

RawReader reader = RawReaderBuilder.
  withInput(inputStream).
  withOutput(someFile).
  withChunkSize().
  build();

Upvotes: 0

Bozho
Bozho

Reputation: 597234

You can use a builder:

Foo foo = new FooBuilder().setFile(..).setChunkSize().build();

Where .build() invokes a constructor of Foo that takes the builder and assigns whichever variables are set. Something like that:

public class Foo {

private Foo(FooBuilder builder) {
    //get whatever you can find from the builder to fill the state of Foo
}
public static FooBuilder {
     private String filename;
     private File file;
     private InputStream stream;
     private int chunkSize;
     // getters and setters
     public Foo build() {
         return new Foo(this);
     }
}

}

Upvotes: 3

Related Questions