Dominik Balczer
Dominik Balczer

Reputation: 21

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();
    }

}

Upvotes: 2

Views: 98

Answers (2)

kaya3
kaya3

Reputation: 51034

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);
}

Upvotes: 0

Mureinik
Mureinik

Reputation: 311163

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();
   }
}

Upvotes: 4

Related Questions