没有instanceof的类型安全委托
我有一个服务例程:
filter(List<Criterion> criteria);
有没有一种好的方法可以内部将方法调用分派到特定Criteria
的类型安全实现,而不涉及instanceof
和不会让 API 变得混乱。
我想要类似以下的东西(但这自然行不通):
filter(List<Criterion> criteria) {
for (Criterion c : criteria) {
dispatch(c);
}
}
dispatch(FooCriterion c) {...}
dispatch(BarCriterion c) {...}
I have a service routine:
filter(List<Criterion> criteria);
Is there a good way to internally dispatch the method call to a typesafe implementation of a specific Criteria
without involving instanceof
and without cluttering the API.
I'd like something like the following (which naturally doesn't work though):
filter(List<Criterion> criteria) {
for (Criterion c : criteria) {
dispatch(c);
}
}
dispatch(FooCriterion c) {...}
dispatch(BarCriterion c) {...}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
虽然它可能被视为混乱,但可以使用类似访问者模式的东西(使用双重调度的原理):
Although it might be viewed as cluttering, something like the Visitor pattern can be used (using the principle of double-dispatch):
听起来您想使用访问者模式。
维基百科文章包含一个 Java 示例。
Sounds like you want to use the visitor pattern.
The wikipedia article contains a Java example.
如果您希望根据对象的类型调用一个且仅一个方法实例,则访问者模式是首选解决方案。
但是,如果您有 C 继承 B 继承 A 并且您希望对象调用其类类型的方法并且全部继承(例如),则必须使用 isAssignableFrom(...)。
例如,如果您的对象类型为 B,并且您希望它调用
dispatch(B obj)
和dispatch(C obj)
,则需要分别将这些调用括起来:永远不要使用instanceof,因为在这种情况下它不起作用。
Visitor pattern is the preferred solution if you want one and only one instance of the method to be called according to the object's type.
However, if you have C inherits B inherits A and you want your objects to call the method for their class type and all inherited (for example), you must use isAssignableFrom(...).
For example, if your object is if type B and you want it to call
dispatch(B obj)
anddispatch(C obj)
, you need to enclose those calls with respectively:Don't ever use instanceof, because it would not work in this case.
另一个解决方案可能是使用以下公共类,但它可能会使您的代码混乱。
导入 org.apache.commons.collections.Predicate;
导入 org.apache.commons.collections.iterators.FilterIterator;
尝试一下。
Another solution could be using following commons classes but it might clutter your code.
import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.iterators.FilterIterator;
Try it out.