3

I'm developing a game in which there're many classes. The game appears like a grid plane. I have a function which can detect whether a grid consist of any kind of specified class of object. This function return true if the grid contain any one of the specified type of object and return false if there's none. However, when the number of classes needed to be detected increase, the parameter list can easily become awfully long, does anyone know how can I resolve that problem? Any design pattern would help? Or my design is acceptable in this case?

public boolean sameClass(int x, int y, String... className) {
    for (Entity entity : entities) {
        if (entity.getX() == x && entity.getY() == y) {
            for (String name : className) {
                if (name == entity.getClassName()) {
                    return true;
                }
            }
        }
    }
    return false;
}

examples of using the method

sameClass(x, y - 1, "Boulder", "Enemy", "Wall")
sameClass(x, y - 1, "Player")
Stephen Fong
  • 697
  • 5
  • 17
  • 2
    First off use `.equals` with Strings, not `==` – GBlodgett Jul 26 '19 at 23:37
  • Why not pass a list instead of var-args? That will likely be easier to use in the long run. Are you sure you will always be passing hard coded Strings? You could create a Set representing groups of names, then pass a group name and do a lookup in the map to get the names... I thin we'd need more context. – Carcigenicate Jul 26 '19 at 23:39
  • Every use of this function may be different, I may want to detect if there's a wall in one place or I may want to detect if there're any equipable – Stephen Fong Jul 27 '19 at 00:08
  • You can consider creating a model class. – Shivam Pokhriyal Jul 27 '19 at 09:13

2 Answers2

4
  1. You can send Collection to your method:
Set<String> params = new HashSet("Boulder", "Enemy", "Wall");  
boolean result = sameClass(x, y - 1, params);
  1. You can use Builder-like pattern:
boolean result = new Checker(x, y - 1)
  .param("Boulder")
  .param("Enemy")
  .param("Wall")
  .check();

Also, if "Boulder", "Enemy", "Wall" are class of unit, it's better to use Enum instead of strings.

=== Example of possible solution ===

public class Checker {

    private int x;
    private int y;
    private Set<Type> params = new HashSet();

    // Entity related code here

    public Checker(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public Checker param(Type type) {
        this.params.add(type);
        return this;
    }

    public boolean check() {
        for (Entity entity : entities) {
            if (entity.getX() == x && entity.getY() == y) {
                return params.contains(entity.getType());
            }
        }
        return false;
    }

    public enum Type {
        BOULDER,
        ENEMY,
        WALL,
        PLAYER
    }
}
Bor Laze
  • 2,458
  • 12
  • 20
3

First of all, don't ever try to compare java strings for equality using '==' unless otherwise you are testing for reference equality only. Rather use .equals() method. Read How do I compare strings in Java? to know more on this aspect.

And, for your actual problem, you can use different techniques. I would prefer to send array of Strings as parameter to keep the method call simple.

Implement your method like below:

public boolean sameClass(int x, int y, String[] className) {
    for (Entity entity : entities) {
        if (entity.getX() == x && entity.getY() == y) {
            for (String name : className) {
                if (name.equals(entity.getClassName())) {
                    return true;
                }
            }
        }
    }
    return false;
}

Then create a class to store all the possible class name check combination you want to check for:

public class ClassNameCollection {
    public static final String[] detectMultiple = new String[]{ "Boulder", "Enemy", "Wall" };
    public static final String[] detectPlayer = new String[]{ "Player" };
}

When using this method, try something like below:

sameClass(x, y - 1, ClassNameCollection.detectMultiple);
sameClass(x, y - 1, ClassNameCollection.detectPlayer);

This is actually similar to the way you are handling it using var..args but one advantage of using this way I have described is, for a particular purpose (in your case- detecting wall, detecting equipable , etc.) you can create array of strings once and can call the method using that array variable multiple number of times without the need of writing those large number of lists of class names several times.

UkFLSUI
  • 5,509
  • 6
  • 32
  • 47