tags:

views:

102

answers:

4
A: 

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.

Toji
That's exactly how I do it right now. But I do have the GetRace function in a different file so that any class could call it to pull the race. Though it might be better to go with that idea and put it in the classes that need it. I think that would work really well. Thanks.
suinswofi
I'm curious: Why the downvote? It's a valid answer, and one that the QA is apparently happy with. If you have a reason (hopefully more than "that's not how I would do it") why this is not a desirable solution, please explain why in the comments. Simply downvoting an answer without explanation isn't beneficial to anyone. (You're free to disagree with me, of course. Just talk about why, please!)
Toji
+1  A: 

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.

djna
I understand that it would be a reference, but the problem is getting that ID then. In this case, I would have to do a lookup through N number of races to find which one it was to successfully write it out to a file. I guess I could store the ID in the Race class as well, but there's not any safeguard mechanisms to prevent say assigning an invalid race to the Player. Doing it the previous way is more messy, but forces this relationship.
suinswofi
Races would have an ID, there would be a foreign key relationship in the database, Person's ID field matching the primary key ID in the Race, ORM tools manage this for you. The management of such many to one realtionships is all pretty standard, it doesn't turn out to be a big deal in the C# and Java worlds. Have a look at how something such as Hibernate works.
djna
A: 

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....

mlimber
A: 

Procedural code gets information then makes decisions. Object-oriented code tells objects to do things. — Alec Sharp

As soon as you start developing software where you get all the information you need, you have stopped developing Object-Oriented Software. Consider:

public class Dog {
  private VoiceBox voiceBox = new VoiceBox();

  public VoiceBox getVoiceBox() {
    return this.voiceBox;
  }
}

It is absurd to write the following:

Dog sparky = new Dog();
VoiceBox voiceBox = sparky.getVoiceBox();
voiceBox.makeSound();

Why does any other class in the system need to use the Dog's voice box, or even need to know about it? If this was real life, you would not first try to extract the voice box from the dog before using it. Rather, you would do:

Dog sparky = new Dog();
dog.bark();

Using:

public class Dog {
  private VoiceBox voiceBox = new DogVoiceBox();

  private VoiceBox getVoiceBox() {
    return this.voiceBox;
  }

  public void bark() {
    VoiceBox voiceBox = getVoiceBox();
    voiceBox.makeSound();
  }
}

Why does another class need the race? To make decisions? If so, then:

public class Player{
  private Race race = new Race();

  public boolean isRace( RaceIdentifier ri ) {
    return getRace().isRace( ri );
  }

  private Race getRace() {
    return this.race;
  }
}

public class Race {
  public boolean isRace( RaceIdentifier ri ) {
    return getRaceIdentifier().equals( ri );
  }
}

Then:

Player gandalf = new Player();
if( gandalf.isRace( WIZARD ) ) {
  ((Wizard)gandalf).vanish();
}

The above code, no matter how race changes, never needs to change. The class encompassing the above snippet need never know about the Race class, effectively decoupling it from the rest of the system. When the Race needs to change (different type, more added, etc.), no other class is affected.

To me, this is the heart of OOP.

Dave Jarvis