Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Better alternative to using Void for optional argument

Tags:

java

oop

generics

I have an interface specifying method that takes a generic type as input which is used to create a URL.

interface UrlGenerator<T> {

    String prepareUrl( T input );

}

There is one implementation that doesn't need the parameter. It uses Void for generic type T.

class StaticUrlGenerator implements UrlGenerator<Void> {

    private final String url;

    public StaticUrlGenerator( String url ) {
        this.url = url;
    }

    @Override
    public String prepareUrl( Void nothing ) {
        return url;
    }

}

The StaticUrlGenerator is awkward to use, as it requires null as an argument to the prepareUrl method.

I could lose the input parameter:

interface UrlGenerator<T> {

    String prepareUrl( T input );

}

Now I have to pass the required input to the implementing class in other way (in constructor). This way I lose the stateless nature of the class, I have to recreate it with different constructor arguments every time I want to change the input.

class SchedulePageUrlGenerator implements UrlGenerator {

    public static final String QUERY_STRING_BASE = "?from=";

    private final String showingBaseUrl;
    private final LocalDate date;

    public SchedulePageUrlGenerator( String showingBaseUrl, LocalDate date ) {
        this.showingBaseUrl = showingBaseUrl;
        this.date = date;
    }

    @Override
    public String prepareUrl() {
        DateTimeFormatter fmt = DateTimeFormat.forPattern( "yyyy-MM-dd" );
        String dateStr = fmt.print( date );
        return showingBaseUrl + QUERY_STRING_BASE + dateStr;
    }

}

I think there must be something fundamentally wrong with my design.

like image 676
prasopes Avatar asked Mar 10 '26 02:03

prasopes


1 Answers

I think there must be something fundamentally wrong with my design.

The only thing wrong is that you are trying to conflate a one argument method and a zero argument method. You just can't do it in Java ... without opening the door to other problems.

Basically you've got three choices:

  • Stick with your current approach and explicitly pass null in the Void case.

  • Add a second (no argument) method to the interface to deal with the Void case, and make it call the one argument method with a null. Your code needs to cope with a null when T is not Void, but it did anyway.

  • Refactor the interfaces so that there are two distinct interfaces, one with a String prepareUrl() and the other with String prepareUrl(T), and implement the former as a special case class.

Personally, options 2 is slightly better than option 1, but the 3rd option is probably going to lead to other problems; e.g. that particular method with its two variants will be an impediment to polymorphic method calls over the entire space of T types.

(Varargs is a bad idea, because that opens the door for multiple arguments which is probably meaningless for your problem.)

like image 130
Stephen C Avatar answered Mar 11 '26 22:03

Stephen C