我想通过公共消息处理器向特定处理程序发送消息
//
// Library code
//
abstract class Processor<M extends MessageHandler<? extends Message>> {
HashMap<Class<Message>, M> handlerMap;
void addHandler(M, Class<Message>);
void run() {
while(true) {
...
}
}
// QUESTION - how to define this to include the fact that H extends M<T>
// actually im just trying to avoid the ugly cast in the client code.
abstract <H extends MessageHandler<T>, T extends Message> void dispatch(H handler, T message);
}
class MessageHandler<T extends Message> {
}
class Message {
}
//
// Client code
//
class ServerMessage extends Message {
...
}
class ServerMessageHandler<T extends Message> extends MessageHandler<T> {
...
void process(T msg, Object... params) {
...
}
}
class ServerProcessor extends Processor<ServerMessageHandler<? extends Message>> {
@Override
<H extends MessageHandler<T>, T extends Message> void dispatch(H handler, T message) {
// QUESTION - how do i get rid of this cast?
((ServerMessageHandler<T>)handler).process(T, ...);
}
}
服务器处理器将处理许多不同的服务器消息,所有这些消息都有自己的子类型,成员等。这些消息中的每一个都将具有单独的处理程序。一些基本消息类将共享处理程序。
我的问题是如何在客户端代码中避免这种丑陋的演员?我似乎无法写出调度方法的签名,以包含我们知道消息处理程序将是M类型(ServerMessageHandler)的事实,并且特定的ServerMessageHandler由T参数化,并且类型为T的消息将在争论清单。
修改
我不介意如果addHandler方法无法获得总类型安全性,我可以做一些运行时检查以确保强制执行正确的关系(我必须更改其签名才能正确地执行此操作)。我的主要目标是以某种方式强制(通过签名)调度方法中的两个关系。被调用的处理程序是M类型的,并且它被T参数化以实际调用此方法,run方法中会有一些未经检查的强制转换(后者又调用dispatch)。但我不介意那里有丑陋。只是试图将它移出ServerProcessor。
答案 0 :(得分:3)
Processor.dispatch
可以使用任何扩展MessageHandler
的类型。
ServerProcessor
中的方法不是完全覆盖Processor.dispatch
- 对于不具有类强制转换异常的ServerMessageHandler
个实例的处理程序,它将失败(我假设{ {1}}不延伸ServerMessageHandler
是一个拼写错误而不是设计;否则它将因所有输入而失败,因为没有MessageHandler
是MessageHandler
;否则只需创建参数的类型{{1 }})。
为什么你会期望以类型安全的方式表达本质上不安全的行为呢?
ServerMessageHandler
的合同是ServerMessageHandler<T>
可以是任何Processor.dispatch
,H
可以是任何消息。如果H只能是处理程序的类型MessageHandler
由T
进行参数化,那么在定义中使用它:
Processor
但是,这又失去了一些东西,因为M与T无关。在Java中没有任何等同于unbind / bind习惯用语的东西,并且看起来分派方法似乎不应该关心子类型消息,或者处理器应该关心 - 您似乎通过M
方法维护混合的消息处理程序类型,在运行时为任何方法获取处理程序,然后希望使其特定于发送中的特定类型方法
处理器是否只处理一种消息类型?如果是,并且您希望类型安全,则将消息类型设置为类型参数。如果它处理在运行时决定的多种消息类型,那么您将无法获得类型的编译时检查。
如果将事件处理循环和机制分离到处理程序,则可以移动强制转换:
abstract class Processor<M extends MessageHandler<? extends Message>> {
...
abstract <T extends Message> void dispatch (M handler, T message);
}
但是,如果循环是从Process.run()代码中的基本事件类型的队列驱动的,那么在类型安全方面它将不会更好,因为addHandler
的唯一版本被调用与/**
* @param <M> message type
*/
class Processor < M > {
Dispatcher<M> dispatcher;
public Processor ( Dispatcher<M> dispatcher ) {
this.dispatcher = dispatcher;
}
void run ( M...messages ) {
for ( M message : messages ) {
// as there is no mechanism in java to get from Class<T> to Foo<T>, this call
// must be made with the wildcard H Foo<?>
dispatcher.dispatch ( message );
}
}
}
interface Dispatcher<M> {
<T extends M> void dispatch ( T message );
}
class Message {
}
class ServerMessage extends Message {
//...
}
interface ServerMessageHandler<T extends ServerMessage> {
//...
void process ( T msg, String param ) ;
}
class ServerDispatcher implements Dispatcher<ServerMessage > {
HashMap < Class < ? extends ServerMessage >, ServerMessageHandler<?> > handlerMap = new
HashMap < Class < ? extends ServerMessage >, ServerMessageHandler<?> > ();
<T extends ServerMessage >
void addHandler ( ServerMessageHandler<T> handler, Class < T > clz ) {
handlerMap.put ( clz, handler );
}
@SuppressWarnings("unchecked")
// cannot use a trick like clz.cast() as we want ServerMessageHandler<T> rather than T
<T extends ServerMessage> ServerMessageHandler<T> getHandler ( Class < ? extends ServerMessage > clz ) {
return ( ServerMessageHandler<T> ) handlerMap.get(clz);
}
@Override
public <T extends ServerMessage>
void dispatch ( T message ) {
ServerMessageHandler<T> serverMessageHandler = getHandler ( message.getClass() );
serverMessageHandler.process ( message, "wibble" );
}
}
一致,并且强制转换隐藏在ServerDispatcher.dispatch
方法中。安全性来自T = ServerMessage
和getHandler()
的对称性,而不是来自类型变量addHandler
的不同绑定。分隔getHandler
和T
表示只有特定Processor
必须知道Dispatcher
和Dispatcher
之间的关系。