简体   繁体   中英

How can I avoid typechecking in this situation

The situation is the following:

We have a game where there are players and items. The game is won when a player has all 3 specific items in their inventory and assembles them (there is only 1 of each of them on the map). Items have a very simple interface, the player can call use() on them. There are other classes implementing the Item interface that have been left out of the snippet. If I were to ignore basic OOP principles I could just say that when the player uses one of these then we iterate over the player's inventory and check if all 3 of these specific types of items are in it. How do I avoid doing this?

public interface Item{
    public void use();
}

public class SpecificItem1 implements Item{
    public void use(){...}
}

public class SpecificItem2 implements Item{
    public void use(){...}
}

public class SpecificItem3 implements Item{
    public void use(){...}
}

public class Player{

    ArrayList<Item> inventory;

    public void didWeWin() {

        int numOfSItems = 0;

        for(Item i : inventory) {
            if(i instanceOf SpecificItem1)
                numOfSItems++;
            if(i instanceOf SpecificItem2)
                numOfSItems++;
            if(i instanceOf SpecificItem3)
                numOfSItems++;
        }

        if(numOfSItems == 3)
            win();
    }

}

You could use getClass() to get an item's class, and then count the number of unique ones:

public void didWeWin() {
   if (inventory.stream().map(Object::getClass).distinct().count() == 3L) {
       win();
   }
}

In case the inventory might contain other kinds of item which are not part of the win condition, checking that there are at least three different kinds of item is insufficient. In that case, you can use the containsAll method to check for the classes of item required for the win condition.

// List.of works in Java 9+, use Arrays.asList for Java 8
private static List<Class<?>> WIN_CONDITION
    = List.of(SpecificItem1.class, SpecificItem2.class, SpecificItem3.class);

public boolean hasWon() {
    return inventory.stream()
        .map(Object::getClass)
        .collect(Collectors.toSet())
        .containsAll(WIN_CONDITION);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM