Search code examples
javadata-structuresenumsinner-classes

Nested Enums with Constructors & Methods?


I'm a Java student (relatively new) working on a game clone in Java as a side project. In the game, the player controls characters. Each character is part of a faction, and each faction has a set list of skills. The skills of one faction can not be used by any other faction. My idea for how to organize this is with nested enums, where a main Skills enum has multiple inner enums (Faction1, Faction2, etc). The idea is that I would be able to access the data for any specific skill using something along the lines of Skills.Faction1.SKILL_NAME, and to be able to access a full list of a faction's skills using Skills.Faction1.values(). A simplified example of a failed implementation of this is as follows:


public enum Skills {
    FACTIONLESS_SKILL("arbitraryArgs"); //More skills than just this one
    
    enum Faction1 {
        FACTION1_FIRST_SKILL("arbitraryArgs"), //More skills between the 2
        FACTION1_LAST_SKILL("arbitraryArgs");
        ...
    }
    
    enum Faction2 {
        FACTION2_FIRST_SKILL("arbitraryArgs"), //More skills between the 2
        FACTION2_LAST_SKILL("arbitraryArgs");
        ...
    }
    
    String arbitraryField; //1 of many fields universal among both factionless and factioned skills
    
    Skills(String arbitraryArgs) { //1 of many universal constructors
        this.arbitraryField = arbitraryArgs;
    }

    void doUniversalThing() {
        //Code here
    }
}

When I try to use this implementation, I get errors telling me that the constructors and/or fields for the values in the inner enums don't exist. I tried copy pasting the constructors and fields into each individual inner enum, however that was both unreadable and unaccommodating to potential future skills which would not be attached to a faction. This simplified example doesn't even include all of the methods and alternate constructors that must be accessible to each skill. How could I implement this idea effectively and elegantly in a way that both supports skills which are a member of a faction and skills which are not, assuming that I could implement it at all? I tried my best to explain the intended results of the code, but if anything is still unclear then just let me know. Thank you.

Edit: The contents of Faction1 were requested, so in additon to me rewriting my initial code example to maybe give a better idea of my intentions, here's a few different ways I've tried Faction1. All were either erroneous or just not ideal.

Attempt 1:

public enum Skills {
    FACTIONLESS_SKILL("arbitraryArgs"); //More skills than just this one
    
    enum Faction1 {
        FACTION1_FIRST_SKILL("arbitraryArgs"), //More skills between the 2
        FACTION1_LAST_SKILL("arbitraryArgs");
    }
    
    String arbitraryField; //1 of many fields universal among both factionless and factioned skills
    
    Skills(String arbitraryArgs) { //1 of many universal constructors
        this.arbitraryField = arbitraryArgs;
    }
}

My first attempt was just this, which gave me an error that The constructor Skills.Faction2(String) is undefined. I understand that this is due to Faction2 being its own class and unable to use a Skills constructor, which is why I then moved to my second attempt.

Attempt 2:

public enum Skills {
    FACTIONLESS_SKILL("arbitraryArgs"); //More skills than just this one
    
    enum Faction1 {
        FACTION1_FIRST_SKILL("arbitraryArgs"), //More skills between the 2
        FACTION1_LAST_SKILL("arbitraryArgs");
        
        String arbitraryField; Duplicates of Skills fields
        
        Faction1(String arbitraryArgs) { //Duplicate of Skills constructor
            this.arbitraryField = arbitraryArgs;
        }
    }
    
    String arbitraryField; //1 of many fields universal among both factionless and factioned skills
    
    Skills(String arbitraryArgs) { //1 of many universal constructors
        this.arbitraryField = arbitraryArgs;
    }
}

This solution technically works, in that there are no errors. However, my issue with this solution is the insane amount of code duplication this causes in my non-reduced program. Every skill has numerous fields, constructors, and methods, whether the skill is assigned to a faction or not. There are also numerous factions that would need to be made. If I ever realized that a field or method or constructor was either unneeded and should be removed or needed and should be created, I would need to create or remove it from every faction individually. This is just honestly not something I want to do on a silly side project.

I haven't thought of any other way to create these inner enums, nor have I seen any in my research, so these are my only 2 implementations so far. I hope this clears things up a bit.


Solution

  • Just decided to upgrade to Java 9 to use Map.of(). Thank you all for your help!