我正在设计一组在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
,所以我只是想到了第一个想到的问题,以简化问题。)
答案 0 :(得分:3)
除了Document
和Folder
接口中缺少的类型参数以及使用ArrayList
(一个实现)之外,你拥有它的方式对我来说似乎没问题而不是List
(界面)。
interface Folder<T extends Document<T>>
{
public List<T> findDocuments();
}
interface Document<T extends Document<T>>
{
public Folder<T> getFolder();
}
使用API是最好的了解方法,假设我们有一个名为Document
的{{1}}实现:
SpreadSheet
然后你有一个名为class SpreadSheet implements Document<SpreadSheet> {
@Override
public Folder<SpreadSheet> getFolder() {
return new SpreadSheetFolder();
}
}
的{{1}}实现:
Folder
然后当您使用API时,您会这样做:
SpreadSheetFolder
它运作得很好。
答案 1 :(得分:2)
这似乎是满足您的需求的一种非常好的方式,不,没有更简单的方法来表达相同的内容(特别是,Java没有语法将类型参数约束为this
的类型)。 / p>
但是,既然你扩展了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
时,kludge就说明了这一点。你也(无意中?)否认自己Collections.unmodifiableList
和朋友的服务。因此,通常会通过声明
List<D> findDocuments();
代替。