Say as an example I have a Player class that has a race via a Race class. These races are fixed in number and are loaded into an array which can be accessed statically.
My question is whether the Player class should have an index ID number which would then need to call the static function getRaceByID(int) to retrieve the Race class to do some internal calculations. Now I could get around having to do this if I was to have the race reference directly in the Player class, but then saving the player to a file becomes problematic. I only want a reference to the Race be stored along with the Player data. Like an ID.
I want to avoid storing a copy of the Race data and instead just reference it. Is there anything I should be doing differently? Are there any patterns to address something like this? Databases deal with IDs, but it doesn't seem to work very well in OO development. Any help is appreciated, thanks.
class Player
{
Race race;
}
In this case I would need to compare this race to the races in my static array so that I can properly write out the index ID. Another solution is to store the ID in the Race class itself so that I can reference it directly from the Race class like so:
race.getID();
Or would it be better to go with something like this to enforce this relationship:
class Player
{
int raceID;
}
Race r = MyFile.getRaceByID(raceID);
// can now use race
What you have in memory does not have to be what you store in a database.
The details will depend upon the language you're using and the Object-to-Database technology.
If you have
Player {
Race myRace;
// etc
}
This does not necesserily imply that you have a copy of the Race, in some languages this would imply a "reference" or "pointer" to a Race.
When you come to store in the database it would be quite normal for just the Id of the race to be stored.
In other words, you don't need to compromise the OO design to achieve the effect you want.
Of some relevance to using IDs in an OO design: Modern C++ Design by Alexandrescu has an excellent chapter on object factories. If you have a big switch statement on your ID, then you could probably benefit from reading this chapter, as it will show you the OO way to handle that sort of thing. As the book says:
The Shape-Drawing example [of polymorphism] is often encountered in C++ books, including Bjarne Stroustrup's classic (Stroustrup 1997). However, most introductory C++ books stop when it comes to loading graphics from a file, exactly because the nice model of having separate drawing objects breaks.... A straightforward implementation is to require each Shape-derived object to save an integral identifier at the very beginning. Each object should have its own unique ID. Then reading a file would look like this:
[code with big switch]
.... The only problem [with this type of code] is that it breaks the most important rules of object orientation: [E.G.,] It collects in a single source file knowledge about all Shape-derived classes in the program....
There's no reason that your ID based concept won't work. It doesn't violate any OO principles, and has several benefits. I see no reason NOT to go that route, especially if you've already determined that it would work well for you.
As an aside, if you want to avoid having static_races[player.race_id]
scattered throughout your code, a simple wrapper function would suffice in maintaining a more "OO feel" (Psudocode, since you haven't stated a language:
function Race Player::GetRace() {
return static_races[this.race_id];
}
Simple, but effective. No need to over complicate things.
精彩评论