【问题标题】:Defining abstract generic class with List<?> members用 List<?> 成员定义抽象泛型类
【发布时间】:2016-02-14 11:51:16
【问题描述】:

即使为此想出一个干净的标题也是一个挑战。

基本思想是定义两个超类:一个用于“子”项,其成员引用其“父”,另一个用于包含子对象的“父”列表。 child->parent 和 parent->child 的链接是对称的。每个父/子超类都有定义和实现附加功能的子类。总是有一个并行的子类,这样child&lt;A&gt;parent&lt;A&gt; 配对。也就是说,parent&lt;A&gt; 将仅包含 child&lt;A&gt; 引用,而 child&lt;A&gt; 将仅引用 parent&lt;A&gt; - 子类型之间没有“交叉”。

我该如何表示?我已经坚持了好几天了,我对多层嵌套泛型类型越有创意,它就越糟糕。这就是我想做的:

abstract class ChildBase<T extends ChildBase<T>> {
    ParentBase<T> parent;
}
abstract class ParentBase<T extends ChildBase<T>>  {
    LinkedList<T> childList;
}
class ChildSub extends ChildBase<ChildSub> {
    // ... class specific stuff
}
class ParentSub extends ParentBase<ChildSub> {
    // ... class specific stuff
}

这是一团糟。我怀疑有一种更简单、直接的方法可以做到这一点,而且可能是完全不同的方向。

【问题讨论】:

  • 我很想知道您为什么需要T 来扩展ChildBase?这些类中是否会有一些方法要求它们是ChildBase?获取节点的兄弟姐妹就是一个例子。如果没有,那么您可以显着简化结构。
  • 正如@sprinter 所说,也许需要深入了解您的问题域才能提供更好的设计。考虑更详细地描述所描述的类的应用。
  • 您是否尝试过寻找基于接口的解决方案而不是继承?就我个人而言,我发现如果你只是解耦类而不是更多地耦合它们,很多这些问题会更容易解决。

标签: java generics inheritance


【解决方案1】:

你的意思是class ParentSub extends ParentBase&lt;ChildSub&gt;

如果您进行这一更改,则一切都会编译。

这是一团糟。我怀疑有一种更简单、直接的方法可以做到这一点,而且可能是完全不同的方向。

实际上,与我见过的其他一些使用泛型的方式相比,这并没有那么糟糕。没有完全不同的方法可以实现您所缺少的。

唯一的选择(我认为你应该认真考虑)是使 ChildBaseParentBase 非泛型,并在必要时使用强制转换。泛型被引入到语言中,以帮助程序员编写正确的、类型安全的程序。当您的类之间存在复杂或循环的关系时,弄清楚如何正确使用泛型变得如此困难和耗时,以至于根本没有使用它们的好处。

【讨论】:

  • 是的,我已经尝试将特定类型的内容添加到子类中(而不是在类之外进行强制转换)。我看到的权衡是在维护中。当需要更改时,我需要更加努力地确保根据需要将它们传播到所有子类;确实,花在循环/嵌套通用方法工作上的时间是浪费的,并且可能导致脆弱的代码在我每次需要更改时都会中断。
  • @ags 模式MyClass&lt;T extends MyClass&lt;T&gt;&gt; 的一个问题(除了非常混乱之外)是它非常严格,因为它不能很好地与继承混合。 (stackoverflow.com/questions/33632871/…)。如果您将来决定扩展ChildSub,您将面临更严重的问题,因为您已经将类型参数固定为ChildSub
【解决方案2】:

我花了一点时间来分析你有什么,我真的不明白有什么问题。你的定义似乎工作得很好。这到底是怎么一团糟?

将您拥有的内容扩展到更具体的内容,例如:

abstract class Child<T extends Child<T>> {

    private final Parent<T> parent;


    protected Child(Parent<T> parent) {
        this.parent = parent;
    }

    Parent<T> getParent() {
        return this.parent;
    }
}

abstract class Parent<T extends Child> {

    private final LinkedList<T> children = new LinkedList<>();

    void addChild(T child) {
        this.children.add(child);
    }

    List<? extends T> getChildren() {
        return Collections.unmodifiableList(this.children);
    }
}

我可以很容易地表达你说你想要表达的想法:

class Daedalus extends Parent<Icarus> { }

class Icarus extends Child<Icarus> {

    public Icarus(Parent<Icarus> parent) {
        super(parent);
    }

}

然后做

Daedalus parent = new Daedalus();
Icarus child = new Icarus(parent);
parent.addChild(child);
for(Icarus aChild : parent.getChildren()) {
    //do something with aChild
}

我一点也不觉得这很乱,从你的问题中我也不清楚为什么这会是一个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-30
    • 1970-01-01
    相关资源
    最近更新 更多