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

2022-09-01 17:24:21

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

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

例如,我有一个继承这个的Book类,并且在重写 use() 时不带任何参数),我有一个 Key 类,它在重写时继承并采用字符串和队列作为参数,等等...

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

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

我尝试过发送对象的变量列表,但对象类型始终是可变的,我不确定在继承类中接收的语法。

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
}

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


答案 1

我一直在努力解决同样的问题,没有一个完美的答案,但我可以给你一些需要考虑的事情。首先,你基本上是在尝试做一些本质上反对面向对象编程的事情,也就是说,你正在尝试创建一个变量接口。接口的要点是,获取对象抽象版本(例如,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() 方法的抽象类呢?但是我说点题外话。无论如何,本书将实现use()方法,如下所示:

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

    // Do what books do with strings and queues
}

我认为这可以满足你的需求,但我认为你应该考虑重构。


答案 2

你想要的是值对象模式

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

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

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

要使用它,假设需要一个类型为的值对象:MyItemMyValueClass

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

推荐