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.
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.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With