Wednesday, December 31, 2014

Composition and Inheritance

One of the architectural decisions to make when building a complex system is how you want to represent the relationship between objects. There are two patterns that are pretty common in gamedev. Composition and Inheritance.

There's been a lot written on both, and I'm not an academic, so I'm sure a lot of my arguments will be simplified or use the wrong terminology.

First, what do the terms mean? For our RPG, let’s say we have a Character class. How do we break that down into enemy vs player?

Inheritance:

We'd have two subclasses:
public class Enemy : Character
public class Player : Character


Each class would implement the logic specific to a player or enemy. The logic and relationships would resolve at compile time.

Composition:

The character class would have a CharacterType attribute, with different types.

   public enum CharacterType
   {
       Player,
       Enemy,
       NPC
   }

The logic of both player and enemy would be included in the character class, and the control would be decided by a switch statement. The logic and relationships would resolve at runtime, once the attribute is set.

For the RPG game, I'm mostly using composition. The benefits are that there aren't as many classes, and I don't have to worry about casting my parent classes into subclasses.

ex:
Enemy e = (Enemy)character;


The drawbacks are that if the data isn't initialized correctly, the wrong logic may execute, and bugs could potentially be more difficult to track down. But from the standpoint of developing the code, using composition can be a lot quicker.

If I want to create a new ability, I simply add a few types, make a new line in my switch statement, and implement the behavior. The alternative would be creating new classes that inherent from parent objects, and then figuring out when/where to instantiate those new classes.

The only instance where I'm using the OO inheritance is in the Item system. Here's the relationship:

Item
UsableItem : Item
Weapon : Item
RangedWeapon : Weapon
Ammo : Item
Armor : Item


In this case, inheritance made sense. Ranged weapons need a lot more attributes then a healing potion. Simply using composition would have left me with lots of empty properties.

The logic I've used when deciding to use Inheritance vs Composition:

If you have lots of items in a set that are pretty similar and could share the same number of methods/attributes - use composition. If you have nested relationships, where the subset items require lots of additional fields or methods, use inheritance.

No comments:

Post a Comment