2013-07-30 4 views
14

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

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

、私は)これを継承し、使用をオーバーライドする場合(引数を取らないBookクラスを持って、私は継承し、オーバーライドする際、引数として文字列とキューを取る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 
} 

誰かが助けや洞察力を提供できるのですか?

+0

'Item it = new Book();'を実行した場合、正しい引数の型が何であるかをコンパイラが知ることができない場合、メソッド 'Book.use(String、Queue);' ?親クラスの変数に 'Item'のサブクラスを持つことを期待していない場合、なぜメソッドは抽象クラスである必要がありますか? – millimoose

答えて

12

私は同じ質問で苦労しましたが、完璧な答えはありませんが、いくつか検討する必要があります。まず、あなたは基本的に、オブジェクト指向プログラミング(これは可変インタフェースを作成しようとしている)に対して本質的に何かをしようとしています。インタフェースのポイントは、オブジェクトの抽象バージョン(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. 
} 

その後、あなたはこのようなアイテムの使用方法を定義できます

public abstract void use(UseParameters params); 

をし、アイテムを使用して、任意のコードが適切にオブジェクトのパラメータを設定する必要があります:

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(文字列とキューを設定する方法を知っている方法)を知っていれば、単にBookを取得して、variaで抽象クラスをスキップする必要はないble use()メソッドはどれですか?しかし、私は逃げる。とにかく、ブックはそのようにのように使用()メソッドを実装します:

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

    // Do what books do with strings and queues 
} 

が、私はそれが何をしたいあなたを取得と思うが、あなたがリファクタリングを検討すべきだと思います。

+0

詳細な回答ありがとうございます。私はまだアプローチを再設計することができます。これは最良の選択肢です。以下の記事で述べるように、いくつかのインターフェースにグループ分けするのに十分な類似性があるかもしれません。そうでない場合は、インターフェイスを放棄して、使用が自分自身に含まれていることを確認することは意味をなさないかもしれません。 – kaledev

5

引数として使用する型が常に可変であれば、ジェネリックを使用する理由はありません。ただ普通のオブジェクトタイプを使用してください:

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

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

考えられる最善の方法は、use()メソッドの動作に従って項目をグループ化することです。

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

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

グループ化された商品(同じメソッドシグネチャ&戻り値のような一般的な)共通の挙動を共有する場合は、この共通の定義を含むことになる親クラスを定義して拡張することができ動作。

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) { 
    } 
} 
0

はい、抽象メソッドにパラメータを提供できますが、派生クラスで記述した実装されたメソッドに同じタイプのパラメータを提供する必要があります。

関連する問題