views:

207

answers:

3

Hi folks,

Given a finite number of items which differ in kind, is it better to represent them with stacked enums and enum constructors, or to subclass them? Or is there a better approach altogether?

To give you some context, in my small RPG program (which ironically is supposed to be simple), a character has different kinds of items in his or her inventory. Items differ based on their type and use and effect.

For example, one item of inventory is a spell scroll called Gremlin that adjusts the Utility attribute. Another item might be a sword called Mort that is used in combat and inflicts damage.

In my RPG code, I now have tried two ways of representing inventory items. One way was subclassing (for example, InventoryItem -> Spell -> AdjustingAttributes; InventoryItem -> Weapon -> Sword) and instantiating each subclass when needed, and assigning values such as names like Gremlin and Mort.

The other way was by stacking enums and enum constructors. For example, I created enums for itemCategory and itemSpellTypes and itemWeaponTypes, and the InventoryItem enum was like this:

public enum InventoryItem {
   GREMLIN(itemType.SPELL, itemSpellTypes.ATTRIBUTE, Attribute.UTILITY),
   MORT(itemType.WEAPON, itemWeaponTypes.SWORD, 30);

   InventoryItem(itemType typeOfItem, itemSpellTypes spellType, Attribute attAdjusted) {
   // snip, enum logic here
   }
   InventoryItem(itemType typeOfItem, itemWeaponTypes weaponType, int dmg) {
   // snip, enum logic here 
   }
   // and so on, for all the permutations of items. 

}

Is there a better Java programming practice than these two approaches? Or if these are the only ways, which of the two is better? Thanks in advance for your suggestions.

+8  A: 

Enums are good if the only hold static data and very minimal logical (preferably no logic at all). If your objects are meant to have different behaviors depending on their kind, it's usually a good idea to implement them as subclasses.

As others mentioned, you're very likely to add attributes to your objects and these attributes won't make sense for all kinds. Eg. a color attribute makes sense for a weapon but not for a spell. In that case weapon and spell should not be in the same enum.

Guillaume
+1 for the concise and accurate answer. Thanks Guillaume.
Arvanem
+1 enums (should) need no logic
stacker
+4  A: 

If you want to add new attributes to the items it could be easier to implement them as subclasses. In this way, if a group of items gets a new attribute it will propagate to all subclasses.

For instance, if all kinds of Weapon gets a certain weight assigned to it, you simply add that attribute to that class. This attribute will then propagate to subclasses.

Regarding other things that are more static in nature, and thus can directly be assigned a type, enums are good. I'm thinking freely here, so I guess a Weapon could have a DamageType assigned to it:

public abstract class Weapon {

public enum DamageType {

 CUT,
 SMASH,
 PIERCE;
}

private DamageType damageType;
Lars Andren
+1 for the practical implementation of the items.
Arvanem
+4  A: 

In the context you describe I would consider using an class hierarchy as opposed to enum definitions and supplementing this hierarchy with interfaces; e.g.

/**
 * Root of class hierarchy.
 */
public interface InventoryItem {
}

/**
 * Additional "parallel" interface implemented by some (but not all)
 * InventoryItems and other non-inventory items.
 */
public interface Usable {
  void use();
}

/**
 * A Spell is in InventoryItem and is also Usable.
 */
public abstract class Spell implements InventoryItem, Usable {
}

public class Gremlin extends Spell {
}

/**
 * A Door is *not* an InventoryItem but can be used.
 */
public class Door implements Usable {
}

The main advantage of this approach is that it allows you to treat a given object in different contexts (as InventoryItems or as a list of Usables). The other reason I would steer clear away from enums is that you're likely to define behaviour on your items (e.g. spell.cast(Person)) and this doesn't sit well in enums IMHO.

Adamski
+1 and selecting your answer because of the accuracy of your answer and the helpful code guide.
Arvanem