25

この問題を解決するエレガントな方法はまだ見つかりません。私は、他のいくつかのクラスが抽象メソッドで継承している抽象クラスを持っています。このメソッドには、さまざまな型の 0 から 4 ~ 5 個の引数を含めることができます。

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

たとえば、これを継承し、use() をオーバーライドするときに引数を取らない Book クラスがあり、オーバーライド時に String と Queue を継承して引数として取る 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
}

私は何か間違ったことをしているのかもしれません - 誰か助けや洞察を提供できますか?

4

5 に答える 5

20

私は同じ質問に苦労しており、完璧な答えはありませんが、考慮すべき点をいくつか挙げることができます. まず、基本的にオブジェクト指向プログラミングに本質的に反することをしようとしています。つまり、変数インターフェイスを作成しようとしています。インターフェイスの要点は、オブジェクトの抽象バージョン (たとえば、Book ではなく Item) を取得するコードが、use() メソッドを呼び出す方法を知っていることです。これは、use() メソッドに何を渡すことができるかを知っている必要があることを意味します。答えが抽象クラスまたはインターフェースの実装に依存する場合、それを使用するコードが、使用している実装の種類 (Book など) を実際に認識していることを確認する必要があります。 () とにかく適切なパラメータで。

ただし、アーキテクチャをリファクタリングせずに、述べたように質問に答える方法があります。データが 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() メソッドを持つ抽象クラスの必要性をスキップしない理由) を指摘したいだけです。とにかく、Book は次のように 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 に答える
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 に答える