这确实令人困惑,因为这两种类型似乎相互依赖而存在A
;B<A>
这在普通的 OOP 中没有多大意义,那它有什么用呢?我为这种模式找到了 3 个用例。
组合变成继承
假设 aNode
有一个子节点列表。通常的设计是通过组合
class Node
ArrayList<Node> children = ...
有时为了小的性能提升,人们使用继承代替
class Node extends ArrayList<Node>
// the super class represents the children...
这有点令人困惑,但没有什么难以理解的。我们知道这只是一种方便,它不会试图传达一个节点是一个节点列表。
LoadableComponent
可以考虑这个用例。可以说,它是一种不如组合方法理想的设计
class ComponentLoader<C>
C get(){...}
class EditIssue
final ComponentLoader<EditIssue> loader = new ComponentLoader<EditIssue>(){
@Override void load(){...}
@Override void isLoaded(){...}
};
EditIssue compo = ...
compo.loader.get().doSomething();
设计者可能会发现这种方法更笨拙。
方法链
而不是写
foo.doA();
foo.doB();
很多人宁愿写
foo.doA().doB();
不幸的是,该语言并不直接支持方法链接,尽管它正在成为一种越来越受欢迎的功能。解决方法是doA()
返回foo
。它有点脏但可以接受。
但是,如果foo
在类型层次结构中,则解决方法被破坏
class Bar
Bar doA()
class Foo extends Bar
Foo doB();
foo.doA().doB(); // doesn't compile, since doA() returns Bar
所以有人呼吁特殊的“自我型”来解决这个问题。假设有一个关键字This
代表“自我类型”
class Bar
This doA()
foo.doA().doB(); // works, doA() returns the type of foo, which is Foo
看来方法链接是“自我类型”的唯一用例,所以语言可能永远不会引入它(最好直接支持方法链接)
人们发现泛型为这个问题提供了一种解决方法
class Bar<This>
This doA()
class Foo extends Bar<Foo>
Foo has a method "Foo doA()", inherited from Bar<Foo>
这是该A extends B<A>
模式最流行的用例。这是一个孤立的解决方法/技巧。它没有在 A 和 B 之间的关系中添加语义。
约束也是一种流行的This
做法
class Bar<This extends Bar<This>>
它丑陋且无用,我强烈建议不要使用它。只需使用“This”作为约定来指示它的用途。
LoadableComponent
也可能属于这个用例。在更简单的设计中,我们可以做
class LoadableComponent
void ensureLoaded()
class EditIssue extends LoadableComponent
EditIssue compo = ...
compo.ensureLoaded();
compo.doSomething();
为了支持最后两行的方法链接,LoadableComponent
设计成现在的形式,这样我们就可以写compo.get().doSomething()
更多元的东西
所以前两个用例是一种黑客攻击。如果A
和之间存在真正的约束B<A>
怎么办?
与其充当普通的超类型,不如说B
是元,它描述了一个类型A
应该具有一些引用A
自身的属性。这不是传统 OOP 意义上的继承,而是更抽象的东西。(虽然它仍然是通过传统的继承机制实现的,但可以想象语言可以将它作为一个独立的概念来推广。)
Comparable
是这个用例。它描述了某种类型可以与自己进行比较。由于它不是传统的 OOP 类型,理想情况下我们不应该使用静态类型声明对象Comparable
。我们在公共方法返回/参数类型中看不到它,它没有多大意义。相反,我们会看到类似
<T extends Comparable<T>>
void sort(List<T>)
这里的方法需要一个符合 Comparable 模式的类型。
(我真的不知道我在本节中在说什么)