1

Documentオブジェクト内にFolderオブジェクトを保持するジェネリック クラスのセットを設計しています。

// Folder, which holds zero or more documents
public interface Folder<DocType extends Document>
{
    // Locate matching documents within the folder
    public ArrayList<DocType> findDocuments(...);
    ...
}

// Document, contained within a folder
public interface Document
{
    // Retrieve the parent folder
    public Folder getFolder();    // Not correct
    ...
}

これらのクラスは、フォルダおよびドキュメント タイプの実際の実装のために拡張されます。問題は、Document.getFolder()メソッドがタイプ のオブジェクトを返す必要があることです。Folder<DocType>ここで、DocTypeは の実際の実装タイプですDocument。つまり、メソッドはそれ自身の具象クラス タイプが何であるかを知る必要があります。

だから私の質問は、Documentクラスが代わりに次のように宣言されるべきかということです:

// Document, contained within a Folder
public interface Document<DocType extends Document>
{
    // Retrieve the parent folder
    public Folder<DocType> getFolder();
    ...
}

または、これを行う簡単な方法はありますか?上記のコードでは、具体的な実装が次のようになっている必要があります。

public class MyFolder
    implements Folder<MyDocument>
{ ... }

public class MyDocument
    implements Document<MyDocument>
{ ... }

Document<MyDocument>には少し奇妙に思える部分です。本当に必要ですか?

(これが重複している場合は申し訳ありません。アーカイブで探していた正確な答えを見つけることができませんでした。)

補遺

上記の元のコードでは が使用されArrayList<DocType>ていましたが、いくつかのポスターが指摘しているようにList、たとえば次のように を返す方がよいでしょう。

    public List<DocType> findDocuments(...);

(そのメソッドは私の問題にとって重要ではなく、実際の API は を返すIteratorため、質問を単純化するために頭に浮かんだ最初のものを使用しました。)

4

2 に答える 2

3

Documentあなたが持っている方法は、インターフェイスとインターフェイスの型パラメーターが欠落していることと、(インターフェイス)の代わりに(実装)をFolder使用していることを除いて、私にとっては問題ないようです。ArrayListList

interface Folder<T extends Document<T>>
{
    public List<T> findDocuments();

}

interface Document<T extends Document<T>>
{
    public Folder<T> getFolder();
}

API を使用するのが最善の方法です。たとえば、Documentcalledの実装があるとしSpreadSheetます。

class SpreadSheet implements Document<SpreadSheet> {

    @Override
    public Folder<SpreadSheet> getFolder() {
        return new SpreadSheetFolder();
    }
}

そして、次のようなFolder実装がありSpreadSheetFolderます。

class SpreadSheetFolder implements Folder<SpreadSheet>{

    @Override
    public List<SpreadSheet> findDocuments() {
        return asList(new SpreadSheet(), new SpreadSheet());
    }
}

次に、API を使用するときは、次のようにします。

Document<SpreadSheet> d = new SpreadSheet();
Folder<SpreadSheet> folder = d.getFolder();

それはうまく動作します。

于 2012-05-29T22:22:27.760 に答える
2

それは要件に対応する適切な方法のように思えますが、同じことを表現するより簡単な方法はありません (特に、Java には型パラメーターを の型に制約する構文がありませんthis)。

ただし、Document と Folder の両方を拡張するため、実際には相互に再帰的な型のバインドが必要になる可能性があります。つまり、あなたのソリューションでは、式

new MyFolder().findDocuments().get(0).getFolder()

Folder<MyDocument>ではありませんMyFolder。それが MyFolder である必要がある場合、ジェネリックは見苦しくなります:

//Folder, which holds zero or more documents
interface Folder<D extends Document<D, F>, F extends Folder<D, F>> {
    ArrayList<D> findDocuments();
}

// Document, contained within a folder
interface Document<D extends Document<D, F>, F extends Folder<D, F>> {
    F getFolder();
}

その後、次を実装できます。

class MyFolder implements Folder<MyDocument, MyFolder> {
    @Override
    public ArrayList<MyDocument> findDocuments() {
        return new ArrayList<>(Collections.singletonList(new MyDocument()));
    }
}

class MyDocument implements Document<MyDocument, MyFolder> {
    @Override
    public MyFolder getFolder() {
        return new MyFolder();
    }
}

そしていま、

MyFolder folder = new MyFolder().findDocuments().get(0).getFolder();

もコンパイルします。

ところで、ArrayListインターフェイスでの使用は非常に制限的Collections.singletonListです。また、(うっかりして?)Collections.unmodifiableListや友人のサービスを拒否します。したがって、通常、次のように宣言することにより、リストの実装を実装者の裁量に任せます。

List<D> findDocuments();

代わりは。

于 2012-05-29T22:50:20.600 に答える