我的班级List
中的Criteria
接口类型为Query
。
List<Criteria> criteria = new ArrayList<Criteria>();
我有Criteria
的几个具体实现。我想给Query
一个迭代我criteria
列表的方法,并根据具体类型执行一些逻辑。
我现在用instanceof
这样做:
for(Criteria c : criteria) {
if(c instanceof ContextualCriteria){
// logic
}
...
}
这是唯一/最好的方式吗?
答案 0 :(得分:8)
逻辑是否合理地属于Criteria
本身?如果是这样,请将其放入Criteria
接口,并为实现Criteria
接口的每个具体类适当地实现它。这显然是 nice 多态方法。
不幸的是,在现实生活中,OO并不总是像那样简单 - 有时将per-type行为放入类型本身是没有意义的,所以你可能需要使用instanceof
代替。您可以潜在地拥有从“条件类”到某个界面的地图,代表要采取的行动,但这很容易变得更加混乱。
通过visitor pattern进行双重调度有时可以稍微改进一下 - 所以逻辑仍然可以在“调用”类中使用单独的方法,但每个Criteria
可以通过单一接口方法将返回调用到正确的方法。就个人而言,我倾向于发现这种情况会增加耦合并迅速变得丑陋,但其他人则会发誓。
答案 1 :(得分:3)
如果Jon Skeet建议逻辑不属于Criteria,那么您可以使用visitor pattern。
在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...
}
这摆脱了实例,但要小心,我发现如果您不熟悉代码,这种模式很难理解。
答案 2 :(得分:1)
嗯,你可以......
if (ContextualCriteria.class.equals(c.getClass()) {
......虽然这只是一种看起来更像是instanceof
的写作方式。 (好吧,差不多:这个测试它是否完全是类,而不是子类的类 - 对于你想要的isAssignableFrom()
)。
摆脱气味的正确方法是在Criteria
中实现一个多态方法,例如在子类中重写。
答案 3 :(得分:1)
界面是策略模式的一半!要根据类型改变逻辑,请尽可能将其推送到接口后面,以便Criteria具有doLogic()。您可以传递该方法,无论您在调用代码中可能需要更改哪些参数,或者返回新信息 - 这些信息非常具体,很难从相关代码中获得建议。
如果一切顺利,您的主叫代码最终
for (Criteria c : criteria) {
c.doLogic();
}
答案 4 :(得分:1)
您还可以在实现Criteria
的类中实现逻辑public interface Criteria {
public void logic();
}
在ContextualCriteria等类中有几个实现 你的循环看起来很干净:
for(Criteria c : criteria) {
c.logic();
}
答案 5 :(得分:0)
您也可以使用:
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 ...
}
答案 6 :(得分:0)
它没有任何问题。
从未使用instanceof
的人只会写玩具应用程序。