Creating a class with many properties

Started by
7 comments, last by Katie 12 years, 11 months ago
Hi. I'm planning on creating a Character class, but I'm worried about having plenty of properties for it. It will have properties such as Strength, Agility, Intelligence, Dexterity, Level, Name, Points, and many more. I'm wondering if it's normal to have so many properties in one class.

The constructor will have so many parameters too...
Advertisement
Pass in archetypes and have them populate the object? So you'd have a "Knight" archetype. Inside the character, it calls the Knight passing itself in to be filled out with the basic setup, then it'll do its own tweaks.

Or you could read the setup out of a file which contains lots of "Strength=XX" type lines. You could even make it parse lines which say "strength=4+d6" That way you don't have to recompile your program just to try out a stronger knight. You can just alter the text file and restart.
I don't think there is a problem with a class having many parameters.

If it bothers you to have a function (in this case the constructor) with to many parameters then just split it up in different functions.
Then you first call SetStrenght, then SetAgility, ...

If you also have e.g. a class for the enemy, then you can share some properties, by using derived classes.
In this case you would get 3 classes. One for the character, one for the enemy and one that stores properties that are used in both.
That would also make your classes smaller.
TGUI, a C++ GUI for SFML
texus.me
I like and use a similar idea to the one Katie posted; I have a general "template" of an entity and then I fill it out with more unique properties later. The first thing I would do is think of someway to store all your properties, I'd suggest xml perhaps. Create a factory to do all the loading and dealing with all the parameters.

CharacterFactory factory;
Character *knight = factory.Load("Knight.xml");
Character *archer = factory.Load("Archer.xml");

and so on. How you implement the factory is up to you, you could give it friend access to the characters, you could use accessors as Texus suggested (but that might be a very big interface with alot of values) or you could fill out some basic struct and pass that in.

CharacterSpec spec;
spec.strenght = 10;
spec.agility = 5;

Character *knight = new Knight(spec);

Personally I would go for loading from a file right away, it will save you alot of recompiling when you want to tweak values and so on.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

Classes with so many properties should be rare. One option is to split the class into groups of related data. For instance Strength, Agility, Dexterity etc could be grouped in a Skills type, and the Character class could have a Skills field.
I ended up making a struct, which will be used by my Character class. I'm a little confused on the importance of structs, I read that classes can pretty much do the same thing, but better. Should I use struct or class for EffortValues?

struct EffortValues
{
private const int DefaultEvs = 0;
private const int MaxEvs = 255;
private const int MinEvs = 0;

#region Fields
private int hpEv;
private int atkEv;
private int defEv;
private int spAtkEv;
private int spDefEv;
private int spdEv;
#endregion

#region Properties
public int HpEv
{
get { return hpEv; }
set { enforeRange(ref hpEv, value); }
}
public int AtkEv
{
get { return atkEv; }
set { enforeRange(ref atkEv, value); }
}
public int DefEv
{
get { return defEv; }
set { enforeRange(ref defEv, value); }
}
public int SpAtkEv
{
get { return spAtkEv; }
set { enforeRange(ref spAtkEv, value); }
}
public int SpDefEv
{
get { return spDefEv; }
set { enforeRange(ref spDefEv, value); }
}
public int SpdEv
{
get { return spdEv; }
set { enforeRange(ref spdEv, value); }
}
#endregion

private void enforeRange(ref int ev, int val)
{
if (val > MaxEvs)
ev = MaxEvs;
else if (val < MinEvs)
ev = MinEvs;
else
ev = val;
}

public void ResetEvs()
{
HpEv = DefaultEvs;
AtkEv = DefaultEvs;
DefEv = DefaultEvs;
SpAtkEv = DefaultEvs;
SpDefEv = DefaultEvs;
SpdEv = DefaultEvs;
}
}
There's nothing wrong with having a large number of members to a class, so long as your design makes sense. Trying to pass too many arguments in a constructor, however, I do not recommend. Below is a link to the class declarations for the characters and enemies in our RPG. As you can see, there are a large number of members for stats like agility, strength, etc. We make use of inheritance so that characters and enemies share the same common set of members and methods to access them. You'll also notice that our constructors take only a small number of arguments, as we use the ID of the character or enemy to look up the data for that actor in our scripts and initialize all of their stats, skills, and equipment there.

http://allacrost.svn...908&view=markup

Hero of Allacrost - A free, open-source 2D RPG in development.
Latest release June, 2015 - GameDev annoucement

In C# classes and structs are quite different. A struct is handled by value and a class by reference. A struct will probably suffice for this type.
[source]
public int SpAtkEv
{
get { return spAtkEv; }
set { enforeRange(ref spAtkEv, value); }
}
[/source]


There are two ways to handle objects like this which are, in essence, bags of data.

If things can actually play with the data, just make them public and let things set and read them.

If you want to opaqueify things, make verb routines which manipulate the object to achieve a task. Don't have some thing read the hit points with the get(), subtract 7 and then write it back with the set(). Instead, give your character a verb routine -- say "sufferAttack(int strength)"

It'll save you ages in faffing about with get/set routines. All they do is pretend to hide the data while actually causing your object's abstraction to leak all over the place.

This topic is closed to new replies.

Advertisement