Hi everyone. I'm new here and also quite new to Java and OO design so this is a bit of a noob question. It's also my first forum post (...anywhere) so I hope I'm not breaking some forum rule like not drinking the kool-aid first... or something.
Let's say you have a hypothetical game that has different types of Races (Humans, Elves, Orcs) along with different types of Personalities (Spellcaster, Thief, Warrior) to choose from so you can mix and match attributes (Orc Spellcaster is an unlikely example). How would you model a game like this using OO and how would you implement it?
At first look, it would seem like you'd have a Race parent class that would be extended by the individual races (Elf extends Race) and then maybe you can use an interface to implement Spellcaster abilities. And maybe the superparent to all of that would be a Player class that keeps track of equipment obtained and money. The only problem is that I don't know how I would implement it. For example, if Player 1 was an Orc Warrior, how would I declare the attributes in the class (assuming it's the Orc class) and how/where would I implement an attack() method? And if it's implementing the Warrior interface to give the player "Warrior" abilities (Strength +2), how would that happen?
I know it's probably not the best explanation but please let me know if the problem needs further clarification. I'm open to all suggestions. Thanks for the help!
Hi Jason, I'm not a guru of OO design, but I find myself quite comfortable using simple ideas when designing models. Just to continue with your example of the attack() method, you should ask yourself some question :
1) Who can do the action "attack" ? Every player ? Or just warriors ? Maybe Spellcasters can't do an attack, just do semething like cast() ? Answering these few questions should point you in the right direction in decide where to put the attack() and cast() methods.
2) Similarly, you must decide who can get new abilities (strength, dexterity) and who can't. If all classes can get them, probably the best solution is to put them in the top class (Player?). Else, I'd try to define an abstract method which triggers the different ones on the implementing classes, something like newLevelReached() (implementing this on Warriors would call a private method raiseAttributes(), while in Spellcasters objects this could call something different like raiseIntelligenceAndMana() ).
Basically, what you should do is :
a) define real entities (players, races, warriors etc.) and how are they related. b) define actions (attack(), raiseSomeAttibute(), rest()) c) define which entity can do which action.
Once you have point (c) done, it should be quite easy understand where to implement the corresponding actions.
Hope I've helped somehow. [ October 07, 2008: Message edited by: Matteo Di Furia ]
Joined: Oct 07, 2008
Hey thanks Matteo. That sounds simple enough and it gives me a clearer picture of how I should start with this.
I guess what I'm having trouble with is how it should be implemented in an application (and how to explain it). Let's say that every player can attack(), castSpell(), and steal() and they are all implemented the same way. But every race would also have a unique special attack - doSpecialAttack().
Now I'm a player who just registered a character as an Orc so let's assume it would have a higher strength attribute than normal. I'd also assume that there is an Orc_Attributes table out there that stores the base orc stats and I'd populate those stats to the Player's table so when the player is fully registered, the new player would have a strength rating of an orc.
Now to code the thing. I'd guess that there would be a main() method in a Game class or something. How would I make Player 1 attack Player 2 given the information above? I mean sure I could instantiate a Player object and call the generic attack() method with the attributes set for that player but what if I wanted to do a doSpecialAttack() that has attributes special to an orc? Would I have to first find out what the player's race is first (getRaceType()) then do a switch statement? Something like:
But that doesn't seem very OO'ish to me. Can someone map out a model of how they would do a game like this so I could understand how a properly OO-designed application would look like? Thanks in advance.
No, that isn't OO at all. Not that you can even get a switch to work on (race).
What you might do is to get them to implement interfaces like thisEach class can then implement different forms of each method, and you can have several interfaces. If some of your Warriors also drink too much, they might implement a Drunkard interface
Interfaces and abstract classes are the greatest thing since sliced bread. I like to think of them as a contract. Any object that wants to use the interface is bound to implement the contract. When the model is done correctly (everything but the main in this case) and the contracts are implemented appropriately the compiler can ensure every Race will have a doSpecialAttack().
The race interface doesn't actually "do anything" on its own. It's just there to tell the world what any specific race would need to implement in order to fulfil it's role as a race. This way, you know that from now on, until forever and always, any class that implements race will have implemented "doSpecialAttack()."
This concept was probably what took me the longest to understand...and understand the reason for it to exist. Sorry for the winded response. [ October 07, 2008: Message edited by: Paul Yule ]
Joined: Oct 07, 2008
Thanks, Paul. That helps out a lot. I'm actually reading through Head First Java at the moment and I figured I'd make up a program to practice. Initially, I thought it would make sense to have some sort of hierarchy like Player class is extended by Human, Elf, and Orc subclasses (because all humans, elves, and orcs are players) and each Human, Elf, and Orc would implement a Warrior, Spellcaster, Thief interface (ex. A Human can be a Warrior, Spellcaster, or Thief but not all at once). But when it came time to actually write it all out, I was having trouble with it. I find it interesting that most of the suggestions used purely interfaces though and I didn't see any subclassing. Thanks again.
Joined: May 12, 2008
Yar, no problem. In this case I believe we first though of interfaces because of your initial requirements. Generally that leads to be the case when you are talking about actions. Personally I find myself leaning toward interfaces when actions are what changes.
so armor implements isWearable interface
however when you need to go further and say something is a something else but has special qualities unique to it I'd just inherit:
helm extends armor. (which through the structure implements isWearable) Or if, as is the case with DND, a Dungeon Master is a special type of player(With more DM specific player controls, like a list of character npcs instead of just a single one) for example.
DungeonMaster extends Player
Also, if you can work
Originally posted by Campbell Ritchie:
into your code base somehow, I see a future full of WIN. [ October 07, 2008: Message edited by: Paul Yule ]
A key element of a "good" software design is a clean, concise set of requirements. At a high-level, a clear definition of "what" the application will do will help further define the necessary requirements.
However, by only defining the high-level requirement, the design process becomes tougher and typically produces a brittle implementation. Defining requirements and writing them down alongside variants and other related items may not seem exciting to a programmer. And, typically the rush to code and compile seems to be the most important aspect.
... a hypothetical game that has different types of Races (Humans, Elves, Orcs) along with different types of Personalities (Spellcaster, Thief, Warrior) to choose from so you can mix and match attributes (Orc Spellcaster is an unlikely example).
The statement above describes different characters in a game. This is not enough to create a "sound" object-oriented design.
First you need to think out the detailed requirements of what the game is about, and define behavior for each type of entity. From this one can create hundreds of object-oriented designs. The goal is to find a good one and work with it, with the understanding that it is ok to change it in the future if required. OO design is an iterative process.
Once you have a design, then to implement it, you need to write code. Programming to inherit from interfaces rather than creating concrete sub-classes is a best practice. [ October 07, 2008: Message edited by: James Clark ]
Joined: Oct 07, 2008
Thanks for the suggestions everyone. As James said, I probably went straight to modeling the problem without actually clearly fleshing out what the problem is first. I'm trying to follow the concepts from the Head First Java book and decided to try to make a quick project to solidify the concepts in my head. I'll probably post up what I ended up coming up with on this thread in the future to see if I can get opinions on how I could tighten it up. Thanks again for the help.