没有instanceof的类型安全委托

发布于 2024-11-15 07:30:27 字数 422 浏览 0 评论 0原文

我有一个服务例程:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

噩梦成真你也成魔 2024-11-22 07:30:27

虽然它可能被视为混乱,但可以使用类似访问者模式的东西(使用双重调度的原理):

public class Dispatcher {
    void dispatch(FooCriterion foo) { .. }
    void dispatch(BarCriterion bar) { .. }
}

class FooCriterion implements Criterion {
   void visit(Dispatcher d) {
      d.dispatch(this);
   }
}

Dispatcher d = new Dispatcher();
for (Criterion c : criteria) {
   c.visit(d);
}

Although it might be viewed as cluttering, something like the Visitor pattern can be used (using the principle of double-dispatch):

public class Dispatcher {
    void dispatch(FooCriterion foo) { .. }
    void dispatch(BarCriterion bar) { .. }
}

class FooCriterion implements Criterion {
   void visit(Dispatcher d) {
      d.dispatch(this);
   }
}

Dispatcher d = new Dispatcher();
for (Criterion c : criteria) {
   c.visit(d);
}
臻嫒无言 2024-11-22 07:30:27

听起来您想使用访问者模式

维基百科文章包含一个 Java 示例。

Sounds like you want to use the visitor pattern.

The wikipedia article contains a Java example.

原谅过去的我 2024-11-22 07:30:27

如果您希望根据对象的类型调用一个且仅一个方法实例,则访问者模式是首选解决方案。

但是,如果您有 C 继承 B 继承 A 并且您希望对象调用其类类型的方法并且全部继承(例如),则必须使用 isAssignableFrom(...)

例如,如果您的对象类型为 B,并且您希望它调用 dispatch(B obj)dispatch(C obj),则需要分别将这些调用括起来:

if (A.isAssignableFrom(obj.getClass())) { dispatchA(obj); }
if (B.isAssignableFrom(obj.getClass())) { dispatchB(obj); }
if (C.isAssignableFrom(obj.getClass())) { dispatchC(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) and dispatch(C obj), you need to enclose those calls with respectively:

if (A.isAssignableFrom(obj.getClass())) { dispatchA(obj); }
if (B.isAssignableFrom(obj.getClass())) { dispatchB(obj); }
if (C.isAssignableFrom(obj.getClass())) { dispatchC(obj); }

Don't ever use instanceof, because it would not work in this case.

欢你一世 2024-11-22 07:30:27
I have only this to suggest with some duplication.
private void filter(List<Criterion> criteria) 
{
 for(FooCriterion c : fetchFooCriterias(criteria))
 {
  dispatch(c);
 }
}
private List<FooCriterion> fetchFooCriterias(List<Criterion> criteria) 
{
 List<FooCriterion> fc = new ArrayList<FooCriterion>();
 for(Criterion c:criteria)
 {
  if(c instanceof BarCriterion)
  {
   fc.add((FooCriterion)c);
  }
 } 
 return fc;
}

另一个解决方案可能是使用以下公共类,但它可能会使您的代码混乱。
导入 org.apache.commons.collections.Predicate;
导入 org.apache.commons.collections.iterators.FilterIterator;

尝试一下。

I have only this to suggest with some duplication.
private void filter(List<Criterion> criteria) 
{
 for(FooCriterion c : fetchFooCriterias(criteria))
 {
  dispatch(c);
 }
}
private List<FooCriterion> fetchFooCriterias(List<Criterion> criteria) 
{
 List<FooCriterion> fc = new ArrayList<FooCriterion>();
 for(Criterion c:criteria)
 {
  if(c instanceof BarCriterion)
  {
   fc.add((FooCriterion)c);
  }
 } 
 return fc;
}

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文