2

I'm a self-taught Engineer, a beginner in Java and I am trying to create a Dungeons and Dragons character creation module for a bigger game to solidify my understanding of core concepts while learning best practices for given scenarios. I have an implementation outline below, but I believe that there are better design choices that I could make.

I am trying to follow SOLID and Composition over Inheritance; I think this plan follows those concepts.

How can I make this implementation design better?

Implementation

It would contain

  • An Interface for character that contain getters and setters for Name, Age, Height, etc...

  • An Interface for character races to encapsulate racial traits into a portable template

  • Multiple classes that implement the Character Interface and the Race Interface for the goal of creating the Character and Class(RPG) of the Character via a Class Factory.

    • This May be a lot of classes to define due to the possibilities of combinations. Is there a better way to instantiate a character object which abstracts the Class and Race into one object.
  • A Class Factory class would have 2 arguments, one for Race and one for Class to create a character object and a switch case statement would take the Race and the Class to determine the Race-Class combination and return a race-class object (character).

    • Same bottle-neck as above.

The Execution

  • The Main class would take user input for the character's Race and the character's Class to call the Class Factory which returns a character object.
    • It might be worth creating a character abstract class that I can use to extend the unique class combination classes so it is easier to understand when handling the character objects.

Like so:

Character character = new ElfWizard();
  • Then it would prompt the user for the characters Name which will be used to call a Setter method for the character.

  • Prompts again for the size specifications(Tiny, Small, Medium, Large, Extra Large) which will also call a setter.

    • Dependening on Race, size choices will be limited via some conditional flow.
  • Base attribute stats at 10 and gives stat points for allocation with a hard cap at 20 which call setters for each input provided.

    • May be tricky to implement in a console application. It would be cool to find out how to do this.
  • Then calls the character object methods for abilities to test.

Summary of Concerns

Is there a better way than sticking everything in Main? Would it be better to create a Character Creation class which will be instantiated in main to call a user creation method which prompts the user for input to create the character object and then prompts for inputs to set the character info?

Are there any current UI frameworks that I can use to prompt input instead of the Console?

I have interest in transforming this into a API later to store values into a database. This is so that I can create a Web Application to work with these methods.

Thank you for any feedback.

  • 2
    IMHO you shouldn't be using OOP like this to model a CRPG, like leaning on the type system heavily to model your game world. You can already see how explosive the inheritance hierarchy gets if you have a separate class for like ElfMage from HumanMage from HumanCleric from GnomeCleric from DwarfFighter and so on. So much simpler is to consider a character's race and class as just data. – Dragon Energy Dec 10 '18 at 8:53
  • 1
    Personally I would just model a Character which isn't even very object-oriented, just a class with public data members and no functions (just a data aggregate). And you can model all the data you need like str, dex, int, wis, cha, the name of the character, their race, their class (possibly dual-class), maybe their backpack/inventory, things like that -- just data. Then a separate subsystem in you codebase might enforce rules like that dwarves have +2 to their constitution and have size constraints. – Dragon Energy Dec 10 '18 at 8:59
  • 3
    Personally I tend to reach for more procedural-style coding when creating CPRGs, not even thinking that much in terms of objects but just data at first. This is a handy article from Eric Lippert: ericlippert.com/2015/05/11/wizards-and-warriors-part-five – Dragon Energy Dec 10 '18 at 9:03
  • 1
    You say you are trying to use composition over inheritance, but your example is the exact opposite of this. Using composition, it should look something like this: Character character = new Character(Race.Elf, CharacterClass.Wizzard); – TheCatWhisperer Jan 2 at 20:42
  • 1
    There are two extremes when defining an object. On the one extreme is the highly ordered type systems found in most languages like Java. Their entire purpose is to let you know early about a mistake. On the other end of the spectrum are the untyped languages. Each object is unique. In between live the Entity Component Systems and Proto Objects. I'd take a serious read on all of these styles because they have a different role to play, and they can even play nicely together. The middle is good here. – Kain0_0 Jan 2 at 22:42
1

Since you are writing in Java and your explanation of the problem relies heavily on data members and not API calls via an interface, I would recommend you to prefer composition over inheritance. Creating a race-class object class (ElfWizard) for every combination is not preferring composition over inheritance.

Moreover, if Size is a character trait and it depends on Race, it's inappropriate to separate it from the Character class since they are cohesive.

I suggest that you will create a Character class with two private data members for Race and Stats classes. Character should expose an API for the user, and implements the logic you've mentioned before setting the values (the Race-Size, the stats limit, etc.).

And because Character/Race/Stats are very cohesive, Race and Stats can be (depending on your requirements) inner classes of Character in your system.

*There are many UI Frameworks for Java, but it's a separate topic.

0

I believe you are trying to run before you can crawl.

As I said in my comment on your question, your example is not composition, just regular inheritance. However, if all you are building is a character stats creator, you do not even need composition or inheritance. These deal with behavior, and since this is a stats creator, and not a game, your characters have no behavior.

Additionally, a factory is not appropriate here; the factory pattern is for your code, not your user. If anything, the builder pattern would be more appropriate here, but even that may be overkill for your application.

The only thing I can imagine (I am not a D&D player) needing an interface would be the character generator itself since different versions of the game may have different rules.

Again, I am not too familiar with D&D other than lurking on RPG Stack Exchange, but I would imagine your class structure would look more like this:

class Character {
     String getName() {} //snipped for brevity
     void setName() {}
     Race getRace() {}
     CharacterClass getClass() {}
     int getStrength(){
         return strengthRoll + getClass().getStrengthBoon() + getRace().getStrengthBoon();
     }
     // ect...
}

class Race
{
     int getStrengthBoon() {}
     void setStrengthBoon() {}
     // ect
}


// building your character
Character character = new Character();
character.setRace(raceDictionary.get(raceName));
character.setClass(classDictionary.get(className));
character.setStrengthRoll(rolledStrength);
character.setDexterityRoll(rolledDex);
  • 1
    Thank you for taking the time to give me some feedback. If I had 15 reputation then I would upvote this. You are right about my nativity with not knowing when to choose different design patterns for a given situation which is why I am here. Thanks! – brndng Jan 3 at 14:11
  • @brndng just glad I could be of help =) keep us updated on how your project goes – TheCatWhisperer Jan 3 at 16:17
  • @brndng also, my advice to you while you are starting out, is to just keep things as simple as possible in terms of architecture (don't worry too much about architecture and don't over-engineer). It's not that simple is always better, it's just when you find problems with your too simplistic approach (and you will), it's easy to go back and fix it; where as a bad complex architecture is very hard to fix – TheCatWhisperer Jan 3 at 16:29
  • 1
    This is solid advice, I will be sure to keep it in mind. I'll let you know how the project goes too! – brndng Jan 3 at 16:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.