如何让这个嵌套通用参数系统正常工作?
所以我正在努力让一个相当复杂的系统运行起来。这是我正在尝试的基础知识。
规则:
abstract class Rule
{
// stuff
}
class ExampleRule extends Rule
{
// stuff
}
处理程序:
abstract class RuleHandler<T extends Rule>
{
Class<T> clazz;
RuleHandler(Class<T> forClass)
{
this.clazz = forClass;
}
abstract void doStuff(T rule);
}
class ExampleRuleHandler extends RuleHandler<ExampleRule>
{
ExampleRuleHandler()
{
super(ExampleRule.class);
}
void doStuff(ExampleRule rule)
{
// stuff
}
}
并将它们捆绑在一起:
class HandlerDispatcher
{
Map<Class<? extends Rule>, RuleHandler<? extends Rule>> handlers;
void register(RuleHandler<? extends Rule> handler)
{
handlers.put(handler.clazz, handler);
}
void doStuff(List<Rule> rules)
{
for(Rule rule : rules)
{
RuleHandler<? extends Rule> handler = handlers.get(rule.getClass());
handler.doStuff(rule);
}
}
}
class Test
{
void main()
{
HandlerDispatcher hd = new HandlerDispatcher();
hd.register(new ExampleRuleHandler());
}
}
到目前为止,我已经尝试了不同参数的各种组合(通配符、受限等),但尚未在没有类型相关错误的情况下进行编译。欢迎任何见解、解决方案或替代方法。
So I'm trying to get a reasonably complicated system working. Here's the basics of what I'm attempting.
Rules:
abstract class Rule
{
// stuff
}
class ExampleRule extends Rule
{
// stuff
}
Handlers:
abstract class RuleHandler<T extends Rule>
{
Class<T> clazz;
RuleHandler(Class<T> forClass)
{
this.clazz = forClass;
}
abstract void doStuff(T rule);
}
class ExampleRuleHandler extends RuleHandler<ExampleRule>
{
ExampleRuleHandler()
{
super(ExampleRule.class);
}
void doStuff(ExampleRule rule)
{
// stuff
}
}
And tying them together:
class HandlerDispatcher
{
Map<Class<? extends Rule>, RuleHandler<? extends Rule>> handlers;
void register(RuleHandler<? extends Rule> handler)
{
handlers.put(handler.clazz, handler);
}
void doStuff(List<Rule> rules)
{
for(Rule rule : rules)
{
RuleHandler<? extends Rule> handler = handlers.get(rule.getClass());
handler.doStuff(rule);
}
}
}
class Test
{
void main()
{
HandlerDispatcher hd = new HandlerDispatcher();
hd.register(new ExampleRuleHandler());
}
}
So far I've attempted various combinations of different parameters (wildcarded, restricted, etc.) and have yet to get this compiling without type-related errors. Any insights, solutions or alternative approaches are welcome.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您正在尝试以运行时方式使用泛型。如果您在编译时不知道需要处理的类型(无论是真实类型还是类型参数本身),则不能使用简单明了的泛型。它只是一个(或主要是)编译时的构造。
在这里,您尝试通用且动态地处理事情。这一般是不可能的。使用原始类型并忍受类型不安全。
我自己,我想说你只是在自找麻烦:
只需这样做:
然后只用它可以处理的类型注册该规则处理程序。
编辑
根据您的评论,您的目标似乎是对界面的用户强制执行您的设计。我支持这样的论点:应该将过滤和处理的概念分开。
也就是说,另一种选择是将类令牌保留在处理程序本身之外并泛化您的注册方法。
在这里,当您使用原始类型 RuleHandler 时,我们会抑制警告。我们仅通过检查来知道它是安全的,通过查看对
map
的访问并查看该类始终与RuleHandler
类型参数匹配。然而,显然只有当客户端调用register()
时没有出现类型安全警告时,这才是安全的(即,它们参数化了对register()
的调用)。(内部 for 循环被添加到
get
上,以便为给定规则子类的子类找到处理程序)You're trying to use generics in a runtime manner. If you don't know at compile time the types you need to handle, (be it a real type or a type parameter itself), you can't use Generics, plain and simple. It's a compile time only (or mostly) construct.
Here, you're trying to handle things both generically and dynamically. That is generally impossible. Use raw types and live with the type unsafety.
Myself, I'd say you're just asking for trouble with this:
Just make it this:
And then only register that rule handler with types it can handle.
Edit
Based on your comment it seems like your goal is to enforce your design on users of your interface. I stand by the argument that you should separate the concept of filtering and handling.
That said, another option is to leave the class token out of the handler itself and generify your register method.
Here, we suppress a warning when you use the raw type RuleHandler. We know that it is safe through inspection only, by looking at accesses to
map
and seeing that the class always matches theRuleHandler
type parameter. However, this will obviously only be safe if there were no type safety warnings for the client when they invokedregister()
(i.e. they parameterized the call toregister()
).(The inner for-loop was added over
get
such that a handler would be found for subclasses of a given Rule subclasses)你无法避免这里未经检查的强制转换。
对于某些类
Thandlers
映射中的每个条目都将Class
与RuleHandler
相关联> 每个条目都不同。Map
的方法没有表达这个限制。您可以做的是创建
Map
的子类,强制每个条目的类型一致性,并在新地图类中执行所有未经检查的强制转换。有关示例,请查看 Guava 的 ClassToInstanceMap。
You cannot avoid unchecked casts here.
Each entry in your
handlers
map relates aClass<T>
to aRuleHandler<T>
, for some classT
that is different for each entry. The methods ofMap
do not express this restriction.What you can do is create a subclass of
Map
that enforces type consistency per entry and perform all the unchecked casts in your new map class.For an example, look Guava's ClassToInstanceMap.
观察到
RuleHandler === 规则处理程序
以下代码是正确的(并且可以编译)
Observing that
RuleHandler<T extends Rule>
impliesRuleHandler<?> === RuleHandler<? extends Rule>
the following code is correct (and compiles)
问题就出在这一行。
编译器不知道 是正确的类,因为您查找了规则类的正确处理程序。您可以替换为
这将产生警告,因为编译器不知道在运行时您将选择正确的类型。如果这让您感到困扰,您可以添加到您的班级。
The problem is this line.
The compiler doesn't know that <? extends Rule> is the right class because you looked up the correct handler for the Rule's class. You can replace with
This will produce a warning because the compiler doesn't know that at runtime, you will pick the right type. If this bothers you, you can add to your class.