Background:
I am currently working on a game, in which there will be several types of furniture such as chairs, tables or paintings for the player to interact with. For this I have created an abstract class GameObject that handles everything all these objects will have in common (such as drawing, holding position variables etc.). The furniture pieces will have a few parameters that differs, such as width and height (integers) and also what happens when the user choose to interact with it (for example: chairs -> if player is close, sit down, tables -> nothing, paintings -> examine independent of distance). Furniture can be created from a menu, that returns some kind of identifier for the selected piece (currently an integer).
The Question:
How should I implement the different pieces of furniture?
One way would be to create a subclass for each piece of furniture. But this has two drawbacks; First it will be hard to manage that many classes, and secondly when the furniture is created, the correct subclass of GameObject will somehow have to be created based on the identifier (see the followup question).
The most logical option to me seems to be to create a general class that takes the width and height parameters in the constructor as well as a runnable/other interface that can be run when the user clicks on the object. The different values could possibly be stored in a database and retrieved based on the identifier, but the problem still arises with the different actions, since the Runnables cannot be stored externally, and that leads back to the same problem as solution 1; Many different classes where one has to be chosen for the current object.
Followup Question:
Depending on the types of furniture and actions it seems possible that more advanced subclasses with additional methods might be required. If so, the problem of choosing which one to implement depending on an identifier remains regardless of the solution to the previous question. I don’t want to use a gigantic switch statement to instantiate different classes, so is there any way around this?
The game is for the Android platform, but there might be future IOS port, so java-specific answers is not preferable, but acceptable.
Its really tough to come up with a perfect design solution for the problem without considering all the if’s and but’s.
However, one crucial part for your game is the relationship between the items (Furniture, painting, etc) and the actions that can be performed on each item. This is how you can model this relationship (Using composition ) :
Action : Interface representing a game action. Contains a a single method called performAction.
SittingAction : A concrete class that implements Action. Represents a game action for sitting. Implements the performAction method to define the code for performing the sitting action.
ExamineAction : A concrete class that implements Action. Represents a game action for examining an item. Implements the performAction method to define the code for performing the examine action.
Similarly, you can define one action per type of action that can be performed in your game.
GameItem : A class representing an item in the game. Contains properties common to all items such as item name, breadth, width, depth, etc and getters and setters for these properties. GameItem ‘has-a’ instance variable of type Action and a constructor that takes an Action parameter to initialize the Action. GameItem also defines a method called onInteraction that you can call when the user interacts with a GameItem. This method will delegate the task of performing the Action associated with a GameItem by calling the performAction method on the Action instance variable. Therefore, any class that instantiate a GameItem must pass the appropriate Action to the GameItem constructor that represents the Action associated with the GameItem. When a user interacts with an item, just call the onIneraction method.
GameController : A class that listens to user events and calls the onIneraction method on the GameItem that was interacted with.
That’s it. Clean and simple. No need for any if else statements to check what action to perform on what item. Simpy instantiate all your GameItem instances with the appropriate Action instances and have your GameController that listen for user inputs call the onIneraction method on the GameItem that was interacted with.