如何在不使用instanceof的情况下查找类型?
我的类 Query
中有一个接口类型 Criteria
的 List
。
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
逻辑是否明显属于
Criteria
本身?如果是这样,请将其放入Criteria
接口中,并为实现Criteria
接口的每个具体类适当地实现它。这显然是很好的多态方法。不幸的是,在现实生活中,面向对象并不总是那么简单 - 有时将每个类型的行为放入类型本身是没有意义的,因此您可能需要使用
instanceof
来代替。您可能可能有一个从“标准类”到代表要采取的操作的某个接口的映射,但这很容易变得更加混乱。通过访问者模式进行双重调度有时可以稍微改进 -因此逻辑仍然可以位于“调用”类中的单独方法中,但每个
Criteria
都可以通过单个接口方法回调用正确的方法。就我个人而言,我倾向于发现这会增加耦合并很快变得丑陋,但其他人对此深信不疑。Does the logic sensibly belong in the
Criteria
itself? If so, put it into theCriteria
interface and implement it appropriately for each concrete class implementing theCriteria
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.如果逻辑不属于 Jon Skeet 建议的标准,那么您可以使用访问者模式 。
在 ConcreteCriteria 中:
在客户端代码中:
这摆脱了 instanceof,但要小心,我发现如果您不熟悉代码,这种模式很难理解。
If the logic does not belong in the Criteria as Jon Skeet suggests, then you could use the visitor pattern.
In ConcreteCriteria:
In the Client code:
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.
好吧,你可以……
尽管这只是一种看起来更奇特的
instanceof
编写方式。 (好吧,几乎:这测试它是否正是该类,而不是子类的类——因为您需要isAssignableFrom()
)。消除气味的正确方法是在 Criteria 中实现多态方法,例如,该方法在子类中被重写。
Well, you can...
... 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 wantisAssignableFrom()
).The right way to get rid of the smell is to implement a polymorphic method in
Criteria
which is overridden in subclasses, for example.界面是策略模式的一半!要根据类型改变逻辑,请尽可能将其推到接口后面,以便 Criteria 有一个 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
您还可以在实现 Criteria 的类中实现逻辑
在 ContextualCriteria 等类中具有多种实现
你的循环看起来很干净:
You could also implement the logic in the classes which implement Criteria
Have several implemetations in classes like ContextualCriteria
And your loop would look clean:
您还可以使用:
请注意 Object#getClass() 返回
c
的运行时类型,因此如果ContextualCriteria
可以被子类化,则无法可靠地使用它。为此,您需要使用 Class#isAssignableFrom():You can also use:
Note that Object#getClass() returns the runtime type of
c
, so you can't reliably use this ifContextualCriteria
can be subclassed for example. To do this you would need to use Class#isAssignableFrom():这并没有什么问题。
从未使用过
instanceof
的人只编写了玩具应用程序。There is nothing wrong with it.
People who never used
instanceof
only wrote toy applications.