我正在尝试创建一个客户端代码可以订阅的通用boradcaster。当任何更改是具体的Reporter_Abstract子类的模式时,客户端代码将被更新(通过ReportListener)。
我知道我在这里使用泛型(例如
)public abstract class Reporter_Abstract<I extends Reporter_Abstract<I>>
感觉很脏),但我不确定如何以另一种方式强制执行这些要求。如何确保在代码中添加的侦听器处理对I的更改,其中I是Reporter_Abstract的子类型
public abstract class Reporter_Abstract<I extends Reporter_Abstract<I>>
{
private final List<ReportListener<I>> _listeners;
/**
* Broadcast change to any attached listeners, skipping the sender
*/
protected final void reportChange( ReportListener<I> sender )
{
List<ReportListener<I>> listeners = collectListeners();
for( ReportListener<I> listener : listeners )
{
try
{
if( sender == null || sender != listener )
{
listener.recognizeChange( (I) this );
}
}
catch( Exception e )
{
_log.error( "Uncaught exception from listener: " + listener, e );
}
}
}
}
public class SomeStateReporter extends Reporter_Abstract<SomeStateReporter>
{
private boolean _isSomeStateActive;
public void setSomeStateActive( boolean isSomeStateActive )
{
if( isSomeStateActive ^ _isSomeStateActive )
{
_isASomeStateActive = isSomeStateActive;
super.reportChange();
}
}
}
public interface ReportListener<T extends Reporter_Abstract<?>>
{
public void recognizeChange( T report );
}
想要听的课程改变
public class ChangeHandlingClass()
{
public void attachSomeStateListener( SomeStateReporter someStateReporter )
{
sometateReporter.addListener( new SomeStateUpdateListener() );
}
private class SomeStateUpdateListener implements ReportListener<SomeStateReporter>
{
@Override
public void recognizeChange( SomeStateReporter report )
{
handleStateChange( report.isSomeStateActive()
}
}
}
如果这是正确的方式(或正确的方式),那么不应该这一行
listener.recognizeChange( (I) this );
允许我在没有演员的情况下使用'this'的参数,并且知道这是我的定义吗?
我离开基地了吗?
答案 0 :(得分:3)
@StriplingWarrior我在这篇文章中讨论了类似的模式:Is there a way to refer to the current type with a type variable?
我想说你在实现这种模式方面并没有偏离轨道,但重要的是要认识到Reporter_Abstract
必须为其子类布局的合同,这些子类负责正确实现它。只要子类使用具有自己类型的类型参数final
,子类必须为I
,以防止其他子类使I
不正确。
Enum采用了类似的模式 - 这是enum
无法扩展的另一个原因,因为其父类Enum
期望其类型参数E
与延伸enum
。
真正的问题是你是否想要这种模式,而不是@Andy suggests。如果您对Reporter_Abstract
的任何子类进行独占控制,那么您尝试做的事情只能安全地完成。
答案 1 :(得分:3)
如果这是正确的方式(或正确的方式),那么不应该这一行
listener.recognizeChange( (I) this );
允许我在没有演员的情况下使用'this'的参数,并且知道这是我的定义吗?
因为有人可能会声明:
class MyEvilReporter extends Reporter_Abstract<SomeStateReporter> {
...
}
至于解决问题,你不能这样做:
interface ChangeListener {
void stateChanged();
}
根据我的经验,听众经常知道他们在听什么,所以不需要这个方法参数,因此不需要与泛型作斗争: - )
答案 2 :(得分:2)
如何确保在代码中添加的侦听器处理对I ...
的更改
在多个代码库中,对我有用的一种模式是,不是根据发件人定义侦听器,而是根据发件人发送的事件来定义。这允许与通知一起发送数据,包括对发件人的引用。
此模式有效:
// Listener type
public interface IEventListener<EVENT> {
public void receiveEvent( @NonNull EVENT event );
}
// Event producer interface
public interface IEventProducer<LISTENER extends IEventListener<EVENT>, EVENT> {
public void addEventListener( @NonNull LISTENER listener );
public void removeEventListener( @NonNull LISTENER listener );
}
// Concrete implementation
public final class EventProducer<LISTENER extends IEventListener<EVENT>,EVENT>
implements IEventProducer<LISTENER, EVENT> { ... }
如果侦听器实际上是发件人,则可以跳过自己。请注意,某些侦听器可能是发件人的内部类。
请注意,生成器实现按组合而不是继承包含在发件人中,这使得它甚至可以在已经拥有超类的类中使用。