我项目中的每个实体基本上都有两种类型,仅通过在类泛型声明中指定父目录类型才能区分。目录本身用泛型声明,因为它们可以链接到相同类型的特定旧目录。
abstract class AbstractCatalog<T extends AbstractCatalog<T>> {
public abstract T getOld();
}
class Catalog1 extends AbstractCatalog<Catalog1> {
@Override
public Catalog1 getOld() { ... }
}
class Catalog2 extends AbstractCatalog<Catalog2> {
@Override
public Catalog2 getOld() { ... }
}
到目前为止,还不错,但问题是,如果我添加一些必须包含指向某种类型目录的链接的实体,它将变得非常麻烦。
例如,
abstract class AbstractCatalogHistory<C extends AbstractCatalog<C>, E extends AbstractHistoryEntry<C, E>> {
public abstract Set<E> getEntries();
}
abstract class AbstractHistoryEntry<C extends AbstractCatalog<C>, E AbstractHistoryEntry<C, E>> {
public abstract E getPrior();
}
class Cat1HistoryEntry extends AbstractHistoryEntry<Catalog1, Cat1HistoryEntry> {
@Override
public Cat1HistoryEntry getPrior() { ... }
}
class Cat2HistoryEntry extends AbstractHistoryEntry<Catalog2, Cat2HistoryEntry> {
@Override
public Cat2HistoryEntry getPrior() { ... }
}
class Catalog1History extends AbstractCatalogHistory<Catalog1, Cat1HistoryEntry> {
@Override
public Set<Cat1HistoryEntry> getEntries() { ... }
}
class Catalog2History extends AbstractCatalogHistory<Catalog2, Cat2HistoryEntry> {
@Override
public Set<Cat2HistoryEntry> getEntries() { ... }
}
因此,在查看这样的层次结构时,要想知道正在发生的事情要困难得多。这个例子绝不是完整的,我应该在我上面提供的类型中嵌套许多类型。
我试图通过这样做来利用可以在编译时进行验证的类型安全代码的优势。但是同时,这样的代码变得非常混乱,因为我必须指定更长的泛型链,同时向层次结构中添加新的类型。
有没有办法处理这种泛型爆炸?
您的示例并不能完全清楚为什么需要为Catalog1
和Catalog2
设置单独的类,但让我们假设已设置了该类。
但是,即使如此,我仍然没有理由为什么引用这些目录的其他所有内容都需要这种重复。如果只想确保它与正确的目录类型相关联,那么这是您真正需要的唯一通用参数:
class CatalogHistory<C extends AbstractCatalog<C>> {
public Set<HistoryEntry<C>> getEntries();
}
class HistoryEntry<C extends AbstractCatalog<C>> {
public HistoryEntry<C> getPrior();
}
但是,如果您实际上在eg中做不同的事情Cat1HistoryEntry
,Cat2HistoryEntry
那么您需要单独的类怎么办?在那种情况下,您显然无法避免使用抽象基类和两个具体实现,但是我认为无需引入泛型类型,然后按照您的方式将它们固定为具体类型:
abstract class AbstractHistoryEntry<C extends AbstractCatalog<C>> {
public abstract AbstractHistoryEntry<C> getPrior();
}
class Cat1HistoryEntry extends AbstractHistoryEntry<Catalog1> {
@Override
public Cat1HistoryEntry getPrior() { ... }
}
class Cat2HistoryEntry extends AbstractHistoryEntry<Catalog2> {
@Override
public Cat2HistoryEntry getPrior() { ... }
}
这里发生了一些事情。首先,考虑AbstractHistoryEntry
。如果您有其中一个,则说明您是在通用级别上工作,不必在意getPrior
返回该类型或具体的子类型-您只需要知道它会返回另一个AbstractHistoryEntry
引用同一目录的对象即可。
如果你有一个具体的Cat1HistoryEntry
参考,但是,你仍然可以得到得到另一个全类型安全Cat1HistoryEntry
出来的getPrior
感谢返回类型的Java中的协方差。
现在变得稍微复杂了-让我们尝试使用以下方法AbstractCatalogHistory
:
abstract class AbstractCatalogHistory<C extends AbstractCatalog<C>> {
public abstract Set<? extends AbstractHistoryEntry<C>> getEntries();
}
class Catalog1History extends AbstractCatalogHistory<Catalog1> {
@Override
public Set<Cat1HistoryEntry> getEntries() { ... }
}
class Catalog2History extends AbstractCatalogHistory<Catalog2> {
@Override
public Set<Cat2HistoryEntry> getEntries() { ... }
}
如您所见,两个具体的子类仍返回一组具体类型Cat1HistoryEntry
和Cat2HistoryEntry
。现在,抽象基类型需要为这些集合表示一个公共超类型,以便您可以以通用方式使用结果。这是通过引入协方差来完成的。
二传手
二传手使事情复杂化了。基本上,如果您有一个通用容器/集合(例如List<T>
或)AbstractCatalogHistory<C>
,并且您希望同时允许添加和检索项目,那么如果您要保证类型安全,就不能再有项目类型的差异。
例如,如果您有一个AbstractCatalogHistory<C>
允许AbstractHistoryEntry<C>
在历史记录中添加任何项目的设置器,那么您就会遇到问题,因为如果您AbstractCatalogHistory<C>
实际上是a,Catalog1History
那么您只希望其中有Cat1HistoryEntry
项目!
这与通用列表存在相同的问题:AList<Cat>
不是a,List<Mammal>
因为您可以向a添加大象List<Mammal>
,但是您不应该向a添加大象List<Cat>
。
如果您坚持的历史记录Catalog1
必须仅包含Cat1HistoryEntry
项目,则一种解决方案是仅将setter添加到中Catalog1History
,而不添加AbstractCatalogHistory<C>
。这样,泛型类将仅用于读取历史记录,而不用于编写历史记录。
但是,回到我的答案的开头:如果您实际上不需要双重具体类,则解决方案仍然非常简单。不幸的是,您仍然没有解释为什么或是否需要这些。如果您真正想要的只是Catalog1
/Catalog2
区别,并且实际上不需要为egCat1HistoryEntry
和进行其他实现Cat2HistoryEntry
,那么以下内容就足够了:
class CatalogHistory<C extends AbstractCatalog<C>> {
public Set<HistoryEntry<C>> getEntries();
public void addEntry(HistoryEntry<C> entry);
}
class HistoryEntry<C extends AbstractCatalog<C>> {
public HistoryEntry<C> getPrior();
public void setPrior(HistoryEntry<C> prior);
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句