2015-05-21 32 views
10

我经常发现自己想要写的形式避免泛型类型形式的Foo <ActualType延伸富<ActualType>>

public class Foo<ActualType extends Foo<ActualType>> 

例如在这样的设置的通用类定义:

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

这里的变化事件只是一个例子。当我想让超类为每个特定的子类提供“个性化”的功能时(不确定如何更好地描述这个更好......),这更多的是我遇到的一个普遍问题在“个性化”之上的事实是ChangeHandler被称为具有实际子类型的对象(Bar)而不是调用处理程序的超类的类型(Foo)。

不知何故这种方法对我来说似乎有点混乱。它实际上允许潜在的问题,因为没有什么能阻止我从那时候定义:

public class Baz extends Foo<Bar> { /* ... */ } 

是否有一个更清洁的替代?

的圣杯将是始终定义包含当前类的一些类型的参数,像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); 
    } 
} 

this.Class会等于Bar,类型为Bar

+0

看不出这是Java的版本[CRTP]的(https://stackoverflow.com/questions/4173254/what-is-the-curiously-recurring-template-pattern-crtp)。这很典型。 – dhke

+0

圣杯会很好,但它不存在(还)。由于继承,静态检查似乎很困难。 – Radiodef

+0

难道你不能'Foo >',用'T'替换'ActualType'的所有出现?不需要'ActualType'。不知道这是什么意思的“更清洁” –

回答

0

这是一个非常抽象的问题。在我看来,“如何使这个更清洁”的简短答案是:只在需要的地方使用泛型。

public class List<T extends List<T>> 

这是什么试图表达(取代)?一个只允许持有(T扩展)其他列表本身持有Ts(List)的列表,这是我们之前知道的列表,它只允许持有...等等。通告的种类,我不明白你会如何结束这样的事情?

public interface ChangeHandler<SourceType> { 
    public void onChange(SourceType source); 
} 

为什么你想在这里使用泛型?如果你想有一个可以处理多种资源类型的变更处理程序,那么你可以创建一个超类,所有的实际源代码都继承它,或者你创建一个由源代码实现的接口。就像那样,你可以精确地指定源代码暴露的内容。或者,源可以在通知时创建源对象而不是传递“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(); 
    } 
} 

你永远不需要演员......或者你呢?我不确定我是否理解这个问题。

+0

假设你的'Foo'有一些'Source'没有的属性(例如'title'),你希望能够编写一个'ChangeHandler'来传递一个'Foo'类型的'source', ,所以它可以做一些事情,比如'myLabel.setText(source.getTitle());'。在你的建议中,'source'(在'onChange'内部)的类型是'Source',即没有标题。因此,你需要编写诸如'myLabel.setText(((Foo)source).getTitle());'的地方。从技术上讲,你现在可以将这个'ChangeHandler'传递给其他'Sources',你应该首先确保'source'甚至是'Foo'类型。 –

+0

@MarkusA。如果你想在源代码中拥有标题,那么你应该在Source类中使用'public abstract String getTitle();'。但是我想你正在寻找不是每个源都有标题的东西,如果你需要投射你想要在编译时检测错误,如果可能的话? – maraca

+0

完全正确!事实上,在很多情况下,“Source”可能非常普遍,甚至不必知道其潜在的子类。特别是如果它是图书馆的一部分。例如,以我的问题中的'Foo'类。您可以设想将其重命名为'AbstractChangeReportingObject'并将其粘贴到库中,以便为任何可能的子类提供变更处理程序管理,无论它们是什么。但是变更处理程序仍然希望传递一个他们正在监视的对象类型的来源,因为“AbstractChangeReportingObject”将是无用的... –

0

我会建议我们只需使用<This>来表示“自我类型”。不需要绑定,因为它看起来很复杂,不能传达意图,也无法强制约束。

public class Foo<This> { 

    private final List<ChangeHandler<This>> handlers = new ArrayList<>(); 

    public void addChangeHandler(ChangeHandler<This> handler) { 
     handlers.add(handler); 
    } 

    @SuppressWarnings("unchecked") 
    protected void reportChange() { 
     for (ChangeHandler<This> handler: handlers) 
      handler.onChange((This)this); 
    } 
} 

注意演员表(This)this

Java generics: Use this type as return type?

相关问题