我正在考虑将此C#库移植到Java和Android
我想移植此界面
public interface IHandle<in T> where T : class
{
void Handle(T message);
}
它需要处理Contravariance,以便它可以处理IHandle<ISomeIntefaceOrBaseClass>
等
该库的用户可以添加订阅者,当收到消息时,我会检查处理程序
subscribers
.OfType<IHandle<T>>();
这可能与Java泛型有关,还是有更多的Java方式&#39;这样做?
答案 0 :(得分:1)
我假设subscribers.OfType<IHandle<T>>();
您希望所有订阅者都拥有IHandle<T>
类型,其中T
是邮件的类型,对吗?
在Java中,您必须稍微更改一下代码,因为因为类型擦除,您无法提供这样的类型。
假设每个类型/类都有一个句柄,你可以这样做:
interface IHandle<T> {
Class<T> getMessageType(); //needed to query the handle for the supported class
void handle( T message );
}
为了创建该界面的实现,您有几个选择:
为每个类创建一个实现:
class SpecialMessageHandle implements IHandle<SpecialMessage> {
public Class<SpecialMessage> getMessageType() { return SpecialMessage.class; }
public handle( SpecialMessage message ) { ... }
}
或者将该类作为参数传递:
class Handle<T> implements IHandle<T> {
Class<T> messageClass;
public Handle( Class<T> msgClass ) { messageClass = msgClass; }
public Class<T> getMessageType() { return messageClass; }
public handle( T message ) { ... }
}
然后你可能有一个地图消息类来处理类和处理订阅者类(例如Guava Multimap):
Map<Class<?>, IHandle<?>> handles = ...;
Multimap<IHandle<?>, Subscriber> subscribers = ...;
请注意,我在这里使用Class<?>
,因为我不知道这些类是否有共同的超类或接口。如果您有一个共同的超类或界面X
,那么您可以使用Class<? extends X>
代替。
另外请注意,我使用IHandle<?>
因为在Java中你无法定义地图,键和值需要使用相同的泛型类型,同时支持不同的键,即你可以&#39;执行Map<Class<T>, IHandle<T>>
,其中每个键都是不同的T
,但只允许符合键的值。
添加句柄如下所示:
handles.put( handle.getMessageType(), handle );
使用消息查询该地图将如下工作:
IHandle<?> handle = handles.get( message.getClass() );
Collection<Subscriber> handleSubscribers = subscribers.get( handle );
请注意,如果您想获得超类的订阅者(例如,如果SpecialMessage extends Message
并且您希望获得订阅Message
的订阅者),那么您需要走上班级层次结构。
以下是您为一个级别做的事情:
handles.get( message.getClass().getSuperclass() );
for( Class<?> interface : message.getClass().getInterfaces() ) {
handles.get( message );
}