我经常发现自己想要编写表单的泛型类定义
public class Foo<ActualType extends Foo<ActualType>>
Run Code Online (Sandbox Code Playgroud)
例如,在这样的设置中:
public interface ChangeHandler<SourceType> {
public void onChange(SourceType source);
}
public class Foo<ActualType extends Foo<ActualType>> {
private final List<ChangeHandler<ActualType>> handlers = new ArrayList<>();
public void addChangeHandler(ChangeHandler<ActualType> handler) {
handlers.add(handler);
}
@SuppressWarnings("unchecked")
protected void reportChange() {
for (ChangeHandler<ActualType> handler: handlers)
handler.onChange((ActualType) this);
}
}
public class Bar extends Foo<Bar> {
// things happen in here that call super.reportChange();
}
public static void main(String[] args) throws IOException {
Bar bar = new Bar();
bar.addChangeHandler(new ChangeHandler<Bar>() {
@Override
public void onChange(Bar source) {
// Do something with the changed object
}
});
}
Run Code Online (Sandbox Code Playgroud)
这里的变化事件只是一个例子.这是一个普遍的问题,每当我想让超类提供对每个特定子类"个性化"的功能时,我就会遇到这个问题(不知道如何更好地表达这一点......在示例中)在"个性化"之上的事实ChangeHandler是,使用实际子类型(Bar)的对象Foo调用而不是调用处理程序的超类()的类型.
不知何故,这种方法对我来说似乎有些混乱.它实际上允许潜在的问题,因为没有什么阻止我定义:
public class Baz extends Foo<Bar> { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
有更清洁的选择吗?
圣杯将是一个总是被定义为包含当前类的类型参数,就像它的静态版本this.getClass()将允许我写这样的东西:
public class Foo {
private final List<ChangeHandler<this.Class>> handlers = new ArrayList<>();
public void addChangeHandler(ChangeHandler<this.Class> handler) {
handlers.add(handler);
}
protected void reportChange() {
for (ChangeHandler<this.Class> handler: handlers)
handler.onChange(this);
}
}
Run Code Online (Sandbox Code Playgroud)
哪里this.Class等于Bar类的类Bar.
这是一个非常抽象的问题。在我看来,“如何使其更干净”的简短答案是:仅在需要的地方使用泛型。
public class List<T extends List<T>>
Run Code Online (Sandbox Code Playgroud)
这是想表达什么(替代)?一个只允许保存(T 扩展)其他列表的列表,这些列表本身保存 Ts(列表),正如我们之前所知,这些列表是只允许保存...的列表,依此类推。有点循环,我不明白你怎么会得到这样的东西?
public interface ChangeHandler<SourceType> {
public void onChange(SourceType source);
}
Run Code Online (Sandbox Code Playgroud)
为什么要在这里使用泛型?如果您想要一个可以处理多种资源类型的更改处理程序,那么您可以创建一个所有实际源继承的超类,或者创建一个由源实现的接口。这样您就可以准确指定源公开的内容。或者,源可以在通知时创建一个源对象,而不是传递“this”(那么它更像是一条消息)。例如:
public interface ChangeHandler {
public void onChange(Source source);
}
public abstract class Source {
private List<ChangeHandler> handlers;
protected int nr;
public Source(int nr) {
this.nr = nr;
}
public abstract Something getSomething();
public String toString() {
return "SRC" + nr;
}
...
private notify(int index) {
handlers.get(i).onChange(this);
}
}
public class Foo extends Source {
public Foo(int nr) {
super(nr);
}
public String toString() {
return super.toString() + "Foo";
}
public Something getSomething() {
return new Something();
}
}
Run Code Online (Sandbox Code Playgroud)
你永远不需要施放……不是吗?我不确定我是否理解这个问题。