使用Void作为可选参数的更好的替代方案

pra*_*pes 3 java oop generics

我有一个接口指定方法,它采用泛型类型作为输入,用于创建URL.

interface UrlGenerator<T> {

    String prepareUrl( T input );

}
Run Code Online (Sandbox Code Playgroud)

有一个实现不需要参数.它使用Void作为通用类型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;
    }

}
Run Code Online (Sandbox Code Playgroud)

StaticUrlGenerator很难使用,因为它需要null作为prepareUrl方法的参数.

我可能会丢失input参数:

interface UrlGenerator<T> {

    String prepareUrl( T input );

}
Run Code Online (Sandbox Code Playgroud)

现在我必须以其他方式(在构造函数中)将所需的输入传递给实现类.这样我就失去了类的无状态特性,每次我想改变输入时,我都必须用不同的构造函数参数重新创建它.

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;
    }

}
Run Code Online (Sandbox Code Playgroud)

我认为我的设计肯定存在根本性的错误.

Ste*_*n C 5

我认为我的设计肯定存在根本性的错误.

唯一不对的是你试图混合一个参数方法和一个零参数方法.你不能用Java做到这一点......没有打开其他问题的大门.

基本上你有三个选择:

  • 坚持你当前的方法并明确传递nullVoid案例.

  • 第二(无参数)方法添加到处理太虚情况下的界面,并使其调用了一个参数方法null.你的代码需要应对null何时T不是Void,但无论如何都要做.

  • 重构的接口,以便有两种不同的接口,一个具有String prepareUrl()和其他与String prepareUrl(T)和实现前者作为一个特例类.

就个人而言,选项2略好于选项1,但第3选项可能会导致其他问题; 例如,具有两个变体的特定方法将阻碍整个T类型空间上的多态方法调用.

(Varargs是一个坏主意,因为这为多个争论打开了大门,这对你的问题可能毫无意义.)