25

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

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

例如,我有一个 Book 类继承这个并且在覆盖 use() 时不接受任何参数,我有一个 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
}

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

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
}

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

4

5 回答 5

20

我一直在努力解决同样的问题,并且没有完美的答案,但我可以给你一些考虑的事情。首先,您基本上是在尝试做一些本质上反对面向对象编程的事情,即您正在尝试创建一个变量接口。接口的重点是获取对象的抽象版本(例如,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 是 Book(这就是它知道设置 String 和 Queue 的方式,那么为什么不直接获取 Book 并跳过需要具有变量 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
}

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

于 2013-07-30T02:02:21.693 回答
10

您想要的是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) {
    }
}
于 2013-07-30T03:05:40.130 回答
5

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

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

public class Book extends Item {
    public void use(Object ... arguments) { ... }
}
于 2013-07-30T01:44:57.887 回答
1

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

例子

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

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

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

于 2013-07-30T02:04:29.710 回答
0

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

于 2017-01-21T14:57:38.927 回答