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>在哪里。这意味着该方法需要知道它自己的具体类类型是什么。DocTypeDocument

所以我的问题是,是否应该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>,但就像几位海报指出的那样,我最好返回 a List,例如:

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

(该方法对我的问题并不重要,并且我的实际 API 返回一个Iterator,所以我只是使用想到的第一件事来简化问题。)

4

2 回答 2

3

你拥有它的方式对我来说似乎没问题,除了DocumentFolder接口中缺少类型参数以及使用ArrayList(实现)而不是List(接口)。

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

}

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

使用 API 是最好的了解方式,假设我们有一个Document被调用的实现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 实现留给实现者自行决定

List<D> findDocuments();

反而。

于 2012-05-29T22:50:20.600 回答