Java泛型设计问题

时间:2009-09-30 09:45:04

标签: java design-patterns generics

我想通过公共消息处理器向特定处理程序发送消息

//
// 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。

1 个答案:

答案 0 :(得分:3)

Processor.dispatch可以使用任何扩展MessageHandler的类型。

ServerProcessor中的方法不是完全覆盖Processor.dispatch - 对于不具有类强制转换异常的ServerMessageHandler个实例的处理程序,它将失败(我假设{ {1}}不延伸ServerMessageHandler是一个拼写错误而不是设计;否则它将因所有输入而失败,因为没有MessageHandlerMessageHandler;否则只需创建参数的类型{{1 }})。

为什么你会期望以类型安全的方式表达本质上不安全的行为呢?

ServerMessageHandler的合同是ServerMessageHandler<T>可以是任何Processor.dispatchH可以是任何消息。如果H只能是处理程序的类型MessageHandlerT进行参数化,那么在定义中使用它:

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 = ServerMessagegetHandler()的对称性,而不是来自类型变量addHandler的不同绑定。分隔getHandlerT表示只有特定Processor必须知道DispatcherDispatcher之间的关系。