Niminim
Niminim

Reputation: 678

Java Object-Oriented Design

I have in mind an idea for my first java project (OO focused). This project is some kind of a very basic roleplaying game (NO GUI, it's very basic), so I have some OOD questions.

A player (no player class is intended, at least for now) can choose a character class (you know, fighter, wizard etc... in the future he might be able to choose a few characters so he can have a party). After the character has been created he can fight against other foes (controlled by the program).

Suggested implementation: I thought about creating an abstract class (with info like Level, Armor class, Abilities (like strength, dexterity, wisdom etc.). and some methods like attack and defend. Other specific classes will extend Character so it looks like:

                           Character (abstract)
                                 Character Class (like fighter)
                                 Level
                                 Hit Points
                                 Current Hit Points
                                 Armor Class
                                    .
                                    .
                                    .
                                 Inventory (List)

                                 Strength
                                 Dexterity
                                 Wisdom


  Fighter       Wizard         Rouge        Cleric   (All extends Character)

Questions:

  1. Using abstract class here is considered as a good design in this case? would you suggest using an interface and change the design ?
  2. Should I make a another class for Abilities like strength, wisdom etc. or it's ok that it's a part of Character ?
  3. Should I make another class for inventory? I think it might be better, right?
  4. Storing data for all weapons, armors, and shield (maybe other stuff in the future) by using enums is a good solution?
  5. Spells - I'm not sure what is a good way to implement them. I can create a spells class, with static methods for each spell (like castFireball, castHeal methods). Casting spells is relevant only to spell casters characters of course (and each character has a known spells list, so he can cast only spells he knows). Is it a good way to implement that? I can also use a txt file and get the relevant data from the file, but I'm not fond of this idea.

Keep in mind that it should be basic, but it should be planned for future changes and additions. It would look like:

How would you like to attack?

  1. Dagger (primary weapon)
  2. Sword
  3. Cast Spell

3

Which spell would you like to cast?

  1. Fireball
  2. Heal
  3. Ice Storm

1

You hit the enemy with a fireball, and dealt 20 damage.

It's very vague, but you get the idea..

Thanks a lot !!

Upvotes: 2

Views: 850

Answers (5)

Aasmund Eldhuset
Aasmund Eldhuset

Reputation: 37940

Generally, class B should be a subclass of A only if there is an is-a relationship between them - that is, if it would make sense to say that any instance of B also is an instance of A. By applying this, you can e.g. see that the character classes are the only viable candidates for subclasses of Character: A Warrior is a Character, but it is not the case that a Weapon is a Character. Instead, there is a has-a relationship between the other classes and Character: a Character has a Weapon. In that situation, you should use composition: the Character class could have a field of the type Weapon (or, more likely, a field of the type List<Weapon>, so that you can have multiple weapons).

But even if you can make a class hierarchy, it's not certain that you should. If the differences between the character classes can wholly be implemented as differences in stats (which are presumably just fields in the class) or some simple ability differences, you might only need the Character class. On the other hand, if the behavioral differences are huge and you'd end up with a bunch of if statements to select the appropriate behavior for various character classes in different situations, it might be wise to introduce subclasses. However, as @plalx and @B. Dalton point out, it is often possible to use composition instead, extracting the behavioral differences to an abstract CharacterAbilities class and its subclasses.

Upvotes: 1

Jiri Tousek
Jiri Tousek

Reputation: 12440

As for weapons, shields and spells, I would model them into two interfaces:

  • PassiveItem - things that modify character's abilities without them needing to perform any actions (e.g. shield increases their defense)
    • This would have some kind of applyEffect() method that modifies the abilities (possibly create a copy of base abilities, then run all passive items' applyEffect() on those to get final abilities with items)
  • ActiveItem - weapons, items and spells that require character's action to have any effect
    • This would have method performAction(Character self, Character target) that would modify the tow combating characters in some way, e.g. HealSpell implementation would increase character's hitpoints stat, Dagger would perform an attack on the target.

Upvotes: 0

Breand&#225;n Dalton
Breand&#225;n Dalton

Reputation: 1639

I would advise against making Character an abstract base-class of (for instance) Fighter. Being a fighter is only an attribute of the character. I simply tells you that he can wield a sword and wear plate-mail, for instance. In some games, it is assumed that a Warrior character will always be a warrior. Then, when requirements change, so that a character can change class to, say, Mage, there is a whole data migration problem rather than simply a change of attributes. K

Keep your inheritance tree as shallow as you can. Use aggregation and composition instead of inheritance when you can.

Upvotes: 1

MikeJ
MikeJ

Reputation: 2437

Classes should have a single responsibility (or more specific a single reason to change)

1) Abstract class looks the way to go, as you can have common behaviour contained in the class, reducing duplication. An interface only defines the 'contract'

2) See opening statement, sounds like another responsibility.

3) See 2

4) Depends on content, classes may be better

5) Maybe a different abstract class inheriting fro character to determine spell properties. Avoid static methods. Also worth looking at a design pattern for spells. Could have an interface with a method 'castSpell' and each spell implements its own functionality.

Plenty of different options - Best to have a go and see what works. If you get stuck, post the code.

Upvotes: 0

Mackie
Mackie

Reputation: 19

  1. Using an abstract class here works very well since all other character classes will be extended from this class and the class itself is never instantiated.

  2. This is a matter of preference, if your abilities are more complex than integers you may consider making them a class, however if all you are doing is adding temporary buffs/debuffs I recommend having two integers for each ability: one for the current ability value and another for your base value without the buffs/debuffs.

  3. Having inventory as a class is a good idea. Some people may be tempted to create an array of inventory items and manipulate it as the game requires. I think creating a separate class keeps everything nicely encapsulated, even if you are just manipulating an array.

  4. Enumerations are useful in creating a weapon but I would also recommend a separate class for this as well. If you use enumerations for all items you may end up having to use a lot of math, specifically division and modular to get item types. Creating an item class and extending it to different item types allows all items to be contained in a common array using the parent class type while giving them different stats/abilities/uses.

  5. Spells can follow similar to the way I described items above (in fact a spell could be an item if you wanted to hold them in your inventory). Make sure to have some enumerations to describe the spell and its function and then a method to interpret these when it is cast.

Upvotes: 0

Related Questions