带有变量参数列表的抽象方法

时间:2013-07-30 01:39:11

标签: java inheritance variadic-functions

我还没有找到解决这个问题的优雅方法。我有一个抽象类,其他几个类继承了一个抽象方法,该方法可以包含0到4-5种不同类型的参数。

public abstract class Item {
public abstract void use();
}

例如,我有一个继承了这个并且在重写use()时没有参数的Book类,我有一个Key类,它继承并在重写时将String和Queue作为参数等等......

我尝试过使用泛型但我必须在实际取决于类时输入使用的数字,例如Item。

public abstract class Item<T,U> {
public abstract void use(T arg1, U arg2); //Number of arguments/types could be more or less
}

我已经尝试发送一个Object变量列表,但是对象类型总是变量的,我不确定在继承类中接收的语法。

public abstract class Item<T> {
public abstract void use(T... arguments);
}

public class Book extends Item<?> {
public void use(?);
}

public class Book extends Item<String, Queue> { //Wrong number of arguments since I can't use Item<T...>
public void use(String str, Queue q); //fails
}

我可能只是做错了什么 - 有人可以提供任何帮助或见解吗?

5 个答案:

答案 0 :(得分:15)

我一直在努力解决同样的问题,并没有一个完美的答案,但我可以给你一些考虑的事情。首先,您基本上是在尝试做一些本质上违反面向对象编程的事情,即您正在尝试创建一个可变接口。接口的关键是获取对象的抽象版本(例如Item而不是Book)的代码知道如何调用use()方法。这意味着他们必须知道可以传递给use()方法的内容。如果答案取决于抽象类或接口的实现,那么你需要确保使用它的代码实际上知道它正在使用什么样的实现(Book等),否则它不会知道如何调用use ()具有适当的参数。听起来你需要严格地重构你的代码。

但是,有一种方法可以回答您提出的问题,而无需重构架构。您可以创建一个类,其中的数据是可能传递给use()方法的所有不同类型的参数,让调用代码设置该类的字段,然后将其传递给use()方法。例如:

public class UseParameters {
    private String string;
    private Queue queue;
    // Any other potential parameters to use(...)

    public void setString(String string) {
        this.string = string;
    }

    public String getString() {
        return string;
    }

    // All of the other accessor methods, etc.
}

然后,你可以在Item中定义use方法:

public abstract void use(UseParameters params);

使用Item的任何代码都必须适当地设置对象的参数:

Item item = // However you're going to get the item
UseParameters params = new UseParameters();
params.setString("good string");
params.setQueue(new Queue());
item.use(params);

我只是想指出,如果上面的代码知道Item是一本书(它是如何知道设置字符串和队列,那么为什么不只是得到一本书并跳过需要一个带有变量使用的抽象类()方法完全?但我离题了。无论如何,本书将实现use()方法,如下所示:

@Override
public void use(UseParameters params) {
    if(params.getString == null || params.getQueue() == null)
        // throw exception

    // Do what books do with strings and queues
}

我认为这可以让你得到你想要的,但我认为你应该考虑重构。

答案 1 :(得分:8)

你想要的是Value Object Pattern

定义一个类,将各种参数类型封装到一个值对象中,并使抽象方法接受此类型的参数。您正在考虑的每个参数变体都有自己的值类。

然后只需在类中添加泛型类型,并让抽象方法接受该类型的参数:

public abstract class Item<V> {
    public abstract void use(V v);
}

要使用它,假设MyItem需要MyValueClass类型的值对象:

public class MyItem extends Item<MyValueClass> {
    public void use(MyValueClass v) {
    }
}

答案 2 :(得分:5)

如果要用作参数的类型总是可变的,我看不出使用泛型的原因。只需使用普通对象类型:

public abstract class Item {
    public abstract void use(Object ... arguments);
}

public class Book extends Item {
    public void use(Object ... arguments) { ... }
}

答案 3 :(得分:1)

我能想到的最好的方法是根据use()方法的行为对项目进行分组。

示例

public abstract class QueueableItem {
    public abstract void use(String, Queue);
}

public abstract class OrdinaryItem{
    public abstract void use(String);
}

如果分组的项目共享一个共同的行为(在相同的方法签名和返回值中很常见),您可以定义和扩展将包含此常见行为定义的父类。

答案 4 :(得分:0)

是的,我们可以为抽象方法提供参数,但必须为我们在派生类中编写的实现方法提供相同类型的参数。