Java 使用Void作为可选参数的更好选择

Java 使用Void作为可选参数的更好选择,java,oop,generics,Java,Oop,Generics,我有一个接口指定方法,该方法将泛型类型作为用于创建URL的输入 interface UrlGenerator<T> { String prepareUrl( T input ); } 现在我必须以另一种方式(在构造函数中)将所需的输入传递给实现类。这样我就失去了类的无状态特性,每次我想要更改输入时,我都必须用不同的构造函数参数重新创建它 class SchedulePageUrlGenerator implements UrlGenerator { publi

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

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

}

我认为我的设计肯定有一些根本性的问题。

您似乎希望为不同的实现计算不同数量的参数

最接近这一点的方法是使用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));
接口生成器{
字符串准备(T…输入);
}
//可以使用
System.out.println(新的StaticUrlGenerator(“url”).prepareUrl());
//或
System.out.println(新的StaticUrlGenerator(“url”).prepareUrl(null));

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

// this is not a good pattern
if (urlGenerator instanceof SchedulePageUrlGenerator) {
    (SchedulePageUrlGenerator)urlGenerator.prepareUrl();
} else {
    urlGenerator.prepareUrl(...);
}
这似乎是一个黑客

综上所述,如果您的接口有更多的方法,并且只有
prepareUrl(…)
不同,那么我认为将
null
作为
Void
参数传递到
prepareUrl(…)
没有问题。我想我需要更多地了解调用框架,以了解如何生成参数,以及为什么
null
参数会出现这样的问题

如果您的接口中有更多方法,另一种选择是同时使用带参数和不带参数的prepare方法:

String prepareUrl( T input );
String prepareUrlNoInput();
然后,根据哪个实现支持哪个,您可以抛出
UnsupportedOperationException
。但是同样,如果您必须执行上面的
instanceof
if
语句,那么我认为
null
参数更好

我想我的设计一定有根本性的问题

唯一的错误是您试图将单参数方法和零参数方法混为一谈。你就是不能用Java来做。。。没有打开其他问题的大门

基本上你有三个选择:

  • 坚持当前方法,在Void情况下显式传递
    null

  • 向接口添加第二个(无参数)方法来处理Void情况,并使其使用
    null
    调用单参数方法。当
    T
    不是
    Void
    时,您的代码需要处理
    null
    ,但它还是处理了

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

就个人而言,方案2略好于方案1,但第三个方案可能会导致其他问题;e、 g.带有两个变体的特定方法将阻碍在
T
类型的整个空间内进行多态方法调用


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

您可以从一开始就使用Varargs签名:
String prepareUrl(T…input)在我看来就像一个Twitter API客户端:-)无论如何。。。在OO中,操作不是由名称定义的,而是由它们的行为定义的。在您的场景中,prepareUrl在不同的类中执行不同的操作。解决方案是为这两个方法指定不同的名称,以区分它们的操作。
// this is not a good pattern
if (urlGenerator instanceof SchedulePageUrlGenerator) {
    (SchedulePageUrlGenerator)urlGenerator.prepareUrl();
} else {
    urlGenerator.prepareUrl(...);
}
String prepareUrl( T input );
String prepareUrlNoInput();