1

I'm writing a game, as part of this players should be able to click on various GUI items and see further details on a specific area of the GUI. I'm mangaing this through an interface Detailable which is implemented by suitable game obects and sends the appropriate information to the JPanel

There are also containers (all of which implement Detailable) that contain other (Detailable implementing) objects. The goal being it is possible to click on a container and, amongst its stats, see its contents which can then be in turn clicked on to see their stats, etc.

The problem I am having is in writing the addToContents(Detailable d) method of my containers. Each container as an ArrayList<String> of the "type" of container - wardrobe, bookcase, etc. I want to be able to add only certain classes to a given container - so a container with a type of "bookcase" will only accept objects of class Book or Curio for example.

What I currently have is:

public boolean addToContents(Detailable d){
        if(this.types.contains("bookcase") && d.getClass().getName().equals("Book")){
            //do some stuff
            //I know "Book" isn't the right syntax, this is just to demo
            return true;
        }
        else if(this.types.contains("bookcase") && d.getClass().getName().equals("Curio")){
            //other stuff
            return true;
        }
        //etc
        else{
             return false;
        }
    }

But this feels like the wrong way of doing it. Is there a better way? Ideally, for sake of easy code, I'd have something like (pseudocode)

Constructor:
private ArrayList<Class> classesAccepted = <list of classes>

addToContents:
if (classesAccepted.contains(d.getClass()){
    add the thingie to contents
    return true
}
else{
     return false;
}

but I can't seem to find a way of adding a list of classes to the constructor - of translating the ArrayList of class names to an ArrayList of references to the actual class.


Containers are currently read from a JSON so comprise two classes:

public class FurnitureType {
    private String name;
    private List<String> type;
    private int cost;
    private String description;
    private int comfortBonus;
    private int capacity;
    //plus getters for all the above
}

public class Furniture implements Detailable, ListSelectionListener{

private String name;
private List<String> types;
private int cost;
private String description;
private int comfortBonus;
private int capacity;
private ArrayList<Detailable> contents;
private transient DetailPanel dp = null;

public Furniture (FurnitureType type){
    this.name=type.getName();
    this.types = type.getType();
    this.cost = type.getCost();
    this.description = type.getDescription();
    this.comfortBonus = type.getComfortBonus();
    this.capacity = type.getCapacity();
    this.contents = new ArrayList();
}
//appropriate getters

public boolean addToContents(Detailable d){
        if(this.types.contains("bookcase") && d.getClass().getName().equals("Book")){
            //do some stuff
            //I know "Book" isn't the right syntax, this is just to demo
            return true;
        }
        else if(this.types.contains("bookcase") && d.getClass().getName().equals("Curio")){
            //other stuff
            return true;
        }
        //etc
        else{
             return false;
        }
    }
@Override
public String toString(){
    return description;
}

@Override
public Icon getBigPic() {
    return null;
}

@Override
public JComponent getStats() {
    Object [] objectContents = contents.toArray();
    JList contentList = new JList(objectContents);
    contentList.setPreferredSize(new Dimension (400, 300));
    contentList.setFixedCellHeight(50);
    contentList.addListSelectionListener(this);
    contentList.setCellRenderer(new CustomCellRenderer());
    //the CustomCellRenderer class simply makes long descriptions into multiline cells
    return contentList;
}

@Override
public void addPanel(DetailPanel dp) {
    this.dp = dp;
}

@Override
public void valueChanged(ListSelectionEvent lse) {
    Detailable d = contents.get(lse.getFirstIndex());
    dp.updatePanel(d);
}
MrB
  • 818
  • 8
  • 28

2 Answers2

2

You can actually use a Map as shown below:

private static Map<String, List<Class<? extends Detailable>>>
       bookcaseContainer = new HashMap<>();

 static {
       //load the bookcaseContainer Map from properties/database
         bookcaseContainer.put("bookcase", list1);
         bookcaseContainer.put("wardrobe", list2);
    }


if(bookcaseContainer.get("bookcase") != null && 
        bookcaseContainer.get("bookcase").contains(d.getClass())) {
        //do something here
 } else if(bookcaseContainer.get("wardrobe") != null && 
        bookcaseContainer.get("wardrobe").contains(d.getClass())) {
        //do something here
 }  
Vasu
  • 21,832
  • 11
  • 51
  • 67
  • Good answer and thanks for all the help. Accepted the other as the code is slightly shorter and I can't accept two, but its a nice solution. – MrB Apr 15 '17 at 02:14
0

If I understand your question correctly, you are looking for something like this

ArrayList <Class<? extends Detailable>> acceptedClasses = new ArrayList<>();

acceptedClasses.add(Bookcase.class);
acceptedClasses.add(OtherAcceptable.class);

and then do something akin to

boolean test = 
    acceptedClasses.stream().anyMatch(clazz -> aClass.isInstance(detailableInstance));

to check if the instance is of an acceptable type

JustDanyul
  • 13,813
  • 7
  • 53
  • 71
  • Simply `new ArrayList<>()` should be fine in Java 7+ – OneCricketeer Apr 14 '17 at 23:48
  • Federico, I should really have ran that though an compiler first. Thanks for pointing it out, fixed the class vs. clazz typo and dealt with the boolean problem as well. Cheers :) – JustDanyul Apr 15 '17 at 13:55