gpt4 book ai didi

java - 庞大的 Java 类层次结构中繁琐的泛型声明

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:16:55 24 4
gpt4 key购买 nike

我的项目中每个实体基本上有两种类型,它们只能通过在类泛型声明中指定父目录类型来区分。目录本身是用泛型声明的,因为它们可以链接到相同类型的特定旧目录。

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();
}

但是,如果您实际上在做不同的事情,例如Cat1HistoryEntryCat2HistoryEntry所以你需要单独的类(class)?在那种情况下,您显然不能绕过抽象基类和两个具体实现,但我认为没有必要引入泛型类型,然后按照您的方式将它们固定为具体类型:

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() { ... }
}

如您所见,两个具体子类仍然返回一组具体类型 Cat1HistoryEntryCat2HistoryEntry .抽象基类型现在需要为这些集合表达一个公共(public)父类(super class)型,以便您可以以通用方式处理结果。这是通过引入协方差来完成的。

二传手

二传手让事情变得有点复杂。基本上,如果你有一个像 List<T> 这样的通用容器/集合或 AbstractCatalogHistory<C> ,并且您希望同时允许添加和检索项目,如果您希望类型安全,则项目类型不能再有差异。

例如,如果您在 AbstractCatalogHistory<C> 中有一个二传手这允许您添加任何 AbstractHistoryEntry<C>项到历史记录,那么你就有问题了,因为如果你的 AbstractCatalogHistory<C>实际上是一个 Catalog1History那么你只想要 Cat1HistoryEntry里面的元素!

这是与通用列表相同的问题:A List<Cat>不是 List<Mammal>因为你可以在 List<Mammal> 中添加一头大象, 但你不应该能够将大象添加到 List<Cat> .

如果您坚持认为 Catalog1 的历史记录必须仅包含 Cat1HistoryEntry项,那么一个解决方案是只向 Catalog1History 添加一个 setter , 而没有到 AbstractCatalogHistory<C> .这样,通用类将仅用于读取历史记录,而不用于编写历史记录。

但是,回到我回答的开头:如果您实际上不需要双重具体类,那么解决方案仍然非常简单。不幸的是,您仍然没有解释为什么或是否需要这些。如果你真正想要的是 Catalog1/Catalog2区别,你实际上并不需要不同的实现,例如Cat1HistoryEntryCat2HistoryEntry ,那么以下内容就足够了:

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);
}

关于java - 庞大的 Java 类层次结构中繁琐的泛型声明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34150473/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com