如何避免在搜索例程中使用instanceof?

时间:2019-06-14 00:31:47

标签: java oop polymorphism

目前,我正在对像这样的项目列表执行线性搜索:

private Item getKey(ArrayList<Item> inventory) {
    for(Item item : inventory) {
        if(item instanceof Key) {
            return item;
        }
    }
    return null;
}

我听说使用instanceof被认为是“代码异味”。通常,为了避免使用instanceof,我会使用多态性(例如this answer中描述的多态性),但是,在这种情况下,我正在努力寻找如何使用它。

所以我想知道是否有一种方法可以消除对instanceof的需求,并可能使用另一种技术,例如多态性,而这种技术更注重OOD?

2 个答案:

答案 0 :(得分:1)

您的情况与您的链接有所不同。在这种情况下,我认为您的代码不是“代码异味”。
正如@shmosel提到

  

此方法中没有此缺陷。

但是您可以使代码更可重用,例如:

private Item getKey(ArrayList<Item> inventory) {
    return getAnItemByType(inventory, Key.class);
}
private Item getAnItemByType(ArrayList<Item> inventory, Class<? extends Item> type) {
    for(Item item : inventory) {
        if(type.isInstance(item)) {
            return item;
        }
    }
    return null;
}

答案 1 :(得分:1)

如果您想要一个使用多态性而不是instanceof的解决方案,则需要在您的超类型中定义一个isKey()方法,并为有资格作为键的子类型覆盖它:

public class Item {

    public boolean isKey() { 
        return false; 
    }
}

class Key extends Item {
    @Override
    public boolean isKey() {
        return true;
    }
}

然后您的解决方案将变为:

private Item getKey(ArrayList<Item> inventory) {
    for(Item item : inventory) {
        if(item.isKey()) {
            return item;
        }
    }
    return null;
}

请注意,这将返回清单中的 first 键。

对于更现代(更紧凑)的代码样式,您可以在stream操作中利用谓词方法isKey()并返回Optional而不是可能为null的键:

private Optional<Item> getKey(ArrayList<Item> inventory) {
    return inventory.stream().filter( item -> item.isKey() ).findFirst();
}