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

时间:2012-08-29 13:30:08

标签: java oop generics

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

interface UrlGenerator<T> {

    String prepareUrl( T input );

}

有一个实现不需要参数。它使用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;
    }

}

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

我可能会丢失input参数:

interface UrlGenerator<T> {

    String prepareUrl( T 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;
    }

}

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

3 个答案:

答案 0 :(得分:5)

  

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

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

基本上你有三个选择:

  • 坚持使用您当前的方法并在Void案例中明确传递null

  • 向接口添加第二个(无参数)方法来处理Void案例,并使用null调用一个参数方法。当null不是T时,您的代码需要应对Void,但无论如何都要做到这一点。

  • 重构接口,以便有两个不同的接口,一个带有String prepareUrl(),另一个带有String prepareUrl(T),并将前者作为特殊案例类实现。

    < / LI>

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

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

答案 1 :(得分:2)

问题是,SchedulePageUrlGenerator确实 UrlGenerator。如果它有不同的论点,那么我认为它不是。如果您的接口有可选参数,那么我想在调用代码中您必须执行以下操作:

// this is not a good pattern
if (urlGenerator instanceof SchedulePageUrlGenerator) {
    (SchedulePageUrlGenerator)urlGenerator.prepareUrl();
} else {
    urlGenerator.prepareUrl(...);
}

这似乎是一个黑客攻击。

所有这些都说,如果你的接口有更多的方法,只有prepareUrl(...)不同,那么我认为将null作为Void参数传递给{{1}没有问题}}。我想我需要看到更多的调用框架,以了解如何生成参数以及为什么prepareUrl(...)参数是一个问题。

另一个替代方案,如果你的界面中有更多方法,那就是两个有和没有参数准备方法:

null

然后你可以抛出String prepareUrl( T input ); String prepareUrlNoInput(); ,具体取决于哪个实现支持哪个。但同样,如果您必须执行上述UnsupportedOperationException instanceof语句之类的操作,那么我认为if参数更好。

答案 2 :(得分:1)

您似乎想为不同的实现重复不同数量的参数。

最接近你的是使用varargs

interface UrlGenerator<T> {
    String prepareUrl(T... input );
}


// can use
System.out.println(new StaticUrlGenerator("url").prepareUrl());

//or
System.out.println(new StaticUrlGenerator("url").prepareUrl(null));