如何在不使用instanceof的情况下查找类型?

发布于 2024-12-04 23:11:45 字数 483 浏览 1 评论 0原文

我的类 Query 中有一个接口类型 CriteriaList

List<Criteria> criteria = new ArrayList<Criteria>();

我有几个 Criteria 的具体实现。我想为 Query 提供一个迭代我的 criteria 列表的方法,并根据具体类型执行一些逻辑。

我目前正在使用 instanceof 这样做:

for(Criteria c : criteria) {
    if(c instanceof ContextualCriteria){
        // logic
    }
    ...
}

这是唯一/最好的方法吗?

I have a List of interface type Criteria within my class Query.

List<Criteria> criteria = new ArrayList<Criteria>();

I have several concrete implementations of Criteria. I want to give Query a method that iterates through my criteria list, and depending on the concrete type, execute some logic.

I'm presently doing this with instanceof like so:

for(Criteria c : criteria) {
    if(c instanceof ContextualCriteria){
        // logic
    }
    ...
}

Is this the only/best way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(7

谢绝鈎搭 2024-12-11 23:11:45

逻辑是否明显属于 Criteria 本身?如果是这样,请将其放入 Criteria 接口中,并为实现 Criteria 接口的每个具体类适当地实现它。这显然是很好的多态方法。

不幸的是,在现实生活中,面向对象并不总是那么简单 - 有时将每个类型的行为放入类型本身是没有意义的,因此您可能需要使用 instanceof 来代替。您可能可能有一个从“标准类”到代表要采取的操作的某个接口的映射,但这很容易变得更加混乱。

通过访问者模式进行双重调度有时可以稍微改进 -因此逻辑仍然可以位于“调用”类中的单独方法中,但每个 Criteria 都可以通过单个接口方法调用正确的方法。就我个人而言,我倾向于发现这会增加耦合并很快变得丑陋,但其他人对此深信不疑。

Does the logic sensibly belong in the Criteria itself? If so, put it into the Criteria interface and implement it appropriately for each concrete class implementing the Criteria interface. This is obviously the nice polymorphic approach.

Unfortunately, in real life OO doesn't always work as simply as that - sometimes it doesn't make sense to put the per-type behaviour in the type itself, so you may need to use instanceof instead. You could potentially have a map from "criteria class" to some interface representing the action to take, but that could easily end up being even messier.

Double-dispatch via the visitor pattern can sometimes improve things a little - so the logic could still be in separate methods in your "calling" class, but each Criteria can call back to the right method via a single interface method. Personally I tend to find this increases coupling and gets ugly quickly, but others swear by it.

等往事风中吹 2024-12-11 23:11:45

如果逻辑不属于 Jon Skeet 建议的标准,那么您可以使用访问者模式

在 ConcreteCriteria 中:

public void accept(CriteriaVisitor v) {
    v.visit(this);
}

在客户端代码中:

public void method() {
    for (Criteria c : criteria) {
        c.accept(this);
    }
}

public void visit(ConcreteCriteria c) {
    // do logic here
}

public void visit(Criteria c) {
    // othervise...
}

这摆脱了 instanceof,但要小心,我发现如果您不熟悉代码,这种模式很难理解。

If the logic does not belong in the Criteria as Jon Skeet suggests, then you could use the visitor pattern.

In ConcreteCriteria:

public void accept(CriteriaVisitor v) {
    v.visit(this);
}

In the Client code:

public void method() {
    for (Criteria c : criteria) {
        c.accept(this);
    }
}

public void visit(ConcreteCriteria c) {
    // do logic here
}

public void visit(Criteria c) {
    // othervise...
}

This gets rid of the instanceof, but be wary, I have found that this pattern is difficult to understand if you are unfamiliar with the code.

池予 2024-12-11 23:11:45

好吧,你可以……

if (ContextualCriteria.class.equals(c.getClass()) {

尽管这只是一种看起来更奇特的 instanceof 编写方式。 (好吧,几乎:这测试它是否正是该类,而不是子类的类——因为您需要 isAssignableFrom())。

消除气味的正确方法是在 Criteria 中实现多态方法,例如,该方法在子类中被重写。

Well, you can...

if (ContextualCriteria.class.equals(c.getClass()) {

... though it's just a fancier-looking way of writing instanceof. (Well, almost: this tests whether it is exactly the class, rather than the class of a subclass -- for that you want isAssignableFrom()).

The right way to get rid of the smell is to implement a polymorphic method in Criteria which is overridden in subclasses, for example.

看春风乍起 2024-12-11 23:11:45

界面是策略模式的一半!要根据类型改变逻辑,请尽可能将其推到接口后面,以便 Criteria 有一个 doLogic()。您可以向该方法传递您可能需要在调用代码中更改的任何参数,或者返回新信息 - 这是非常特定于实现的,并且很难从相关代码中提供建议。

如果一切顺利,您的调用代码就会结束

for (Criteria c : criteria) {
    c.doLogic();
}

An interface is halfway to the strategy pattern! To vary the logic based on type, push it behind the interface if possible, such that Criteria has a doLogic(). You can pass that method whatever parameters you might need to alter in the calling code, or return new information - that is very implmentation specific and hard to advice on from the code in question.

If all goes well, your calling code ends up

for (Criteria c : criteria) {
    c.doLogic();
}
黑寡妇 2024-12-11 23:11:45

您还可以在实现 Criteria 的类中实现逻辑

public interface Criteria {
  public void logic();
}

在 ContextualCriteria 等类中具有多种实现
你的循环看起来很干净:

for(Criteria c : criteria) {  
   c.logic();
}  

You could also implement the logic in the classes which implement Criteria

public interface Criteria {
  public void logic();
}

Have several implemetations in classes like ContextualCriteria
And your loop would look clean:

for(Criteria c : criteria) {  
   c.logic();
}  
执妄 2024-12-11 23:11:45

您还可以使用:

for(Criteria c : criteria) {
   if(c.getClass() == ContextualCriteria.class){
       // logic
   }
   if ...
}

请注意 Object#getClass() 返回 c 的运行时类型,因此如果 ContextualCriteria 可以被子类化,则无法可靠地使用它。为此,您需要使用 Class#isAssignableFrom()

for(Criteria c : criteria) {
   if(ContextualCriteria.class.isAssignableFrom(c)){
       // logic
   }
   if ...
}

You can also use:

for(Criteria c : criteria) {
   if(c.getClass() == ContextualCriteria.class){
       // logic
   }
   if ...
}

Note that Object#getClass() returns the runtime type of c, so you can't reliably use this if ContextualCriteria can be subclassed for example. To do this you would need to use Class#isAssignableFrom():

for(Criteria c : criteria) {
   if(ContextualCriteria.class.isAssignableFrom(c)){
       // logic
   }
   if ...
}
慢慢从新开始 2024-12-11 23:11:45

这并没有什么问题。

从未使用过 instanceof 的人只编写了玩具应用程序。

There is nothing wrong with it.

People who never used instanceof only wrote toy applications.

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