带有构造函数的嵌套枚举方法?

发布于 2025-01-15 03:37:37 字数 3273 浏览 2 评论 0原文

我是一名 Java 学生(相对较新),正在研究 Java 中的游戏克隆作为业余项目。在游戏中,玩家控制角色。每个角色都是一个派系的一部分,每个派系都有一套技能列表。一个派系的技能不能被其他派系使用。我关于如何组织它的想法是使用嵌套枚举,其中主 Skills 枚举具有多个内部枚举(Faction1Faction2 等)。我的想法是,我将能够使用类似于 Skills.Faction1.SKILL_NAME 的内容来访问任何特定技能的数据,并能够使用 <代码>Skills.Faction1.values()。失败实现的简化示例如下:


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

当我尝试使用此实现时,我收到错误消息,告诉我内部枚举中的值的构造函数和/或字段不存在。我尝试将构造函数和字段复制粘贴到每个单独的内部枚举中,但这既不可读,也不适应未来潜在的技能,这些技能不会附属于某个派系。这个简化的示例甚至不包括每种技能必须可访问的所有方法和备用构造函数。假设我可以实现它,我怎样才能有效而优雅地实现这个想法,既支持派系成员的技能,又支持非派系成员的技能?我尽力解释代码的预期结果,但如果仍有任何不清楚的地方,请告诉我。谢谢。

编辑:请求了 Faction1 的内容,因此除了我重写最初的代码示例以便更好地了解我的意图之外,这里还有我尝试过 Faction1< 的几种不同方法/代码>。所有这些要么是错误的,要么就是不理想。

尝试 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;
    }
}

我的第一次尝试就是这样,这给了我一个错误:构造函数 Skills.Faction2(String) 未定义。我知道这是由于 Faction2 是它自己的类并且无法使用 Skills 构造函数,这就是我随后进行第二次尝试的原因。

尝试 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;
    }
}

此解决方案技术上有效,因为没有错误。然而,我对这个解决方案的问题是,这在我的非简化程序中导致了大量的代码重复。每个技能都有无数的字段、构造函数和方法,无论该技能是否分配给一个派系。还需要建立许多派系。如果我意识到某个字段、方法或构造函数要么不需要并且应该删除,要么需要并且应该创建,那么我需要单独从每个派系创建或删除它。老实说,这不是我想在一个愚蠢的副业项目中做的事情。

我没有想到任何其他方法来创建这些内部枚举,我在研究中也没有看到任何方法,所以这是迄今为止我仅有的两个实现。我希望这能让事情澄清一点。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

書生途 2025-01-22 03:37:37

首先是一个简短的 OOP 课程——
FactionSkill 实体似乎具有has 关系,即A Factions 有一组技能。另外,我将创建一个额外的枚举 SkillName,它再次与 Skill 具有 HAS A 关系。因此,记住这些,您可以像这样安排枚举 --

public enum Faction {
    FACTION1(new HashMap<SkillName, Skill>(){{
        put(Skill.SNIPER_SHOT.skillName(), Skill.SNIPER_SHOT);
    }}),
    FACTION2(new HashMap<SkillName, Skill>(){{
        put(Skill.JUDGEMENT.skillName(), Skill.JUDGEMENT);
    }});

     Map<SkillName, Skill> skills;
    Faction(Map<SkillName, Skill> skills) {
        this.skills = skills;
    }

    public Skill[] skills(){
        return this.skills.values().toArray(new Skill[0]);
    }

    public Skill skill(SkillName name){
        Skill skill =  this.skills.get(name);
        if(Objects.isNull(skill)){
            throw new IllegalArgumentException("Invalid Skill name");
        }
        return skill;
    }

}

enum SkillName {
    SNIPER_SHOT("SNIPER_SHOT"),
    JUDGEMENT("JUDGEMENT");
    String value;

    SkillName(String value){
        this.value = value;
    }

}

enum Skill {
    SNIPER_SHOT(SkillName.SNIPER_SHOT, 0, 95, 5, new boolean[] {true, true, false, false}, new boolean[] {false, true, true, true}),
    JUDGEMENT(SkillName.JUDGEMENT,-25, 85, 5, new boolean[] {true, true, false, false}, new boolean[] {true, true, true, true});
    SkillName name;
    Integer dmg;
    Integer acc;
    Integer crit;
    boolean[] rank;
    boolean[] target;
    Skill(SkillName name, Integer dmg, Integer acc, Integer crit, boolean[] rank, boolean[] target) {
        this.name = name;
        this.dmg = dmg;
        this.acc = acc;
        this.crit = crit;
        this.rank = rank;
        this.target = target;
    }

    public SkillName skillName() {
        return this.name;
    }
}

现在您可以像这样访问技能和特定技能, --

Faction.FACTION1.skills();
Faction.FACTION2.skills();
Faction.FACTION1.skill(SkillName.SNIPER_SHOT);
Faction.FACTION1.skill(SkillName.JUDGEMENT); // this should throw exception
Faction.FACTION2.skill(SkillName.SNIPER_SHOT); // this should throw exception
Faction.FACTION2.skill(SkillName.JUDGEMENT);

访问模式与您想要的不完全相同,但这些工作的程度几乎相同。

旁注 -

不确定您正在开发什么类型的游戏,但在大多数游戏中,玩家的技能会提高(即技能属性发生变化)并且玩家也会获得新技能。因此,上述设置将变得非常严格,因为枚举是不可变的,您将无法扩展它。相反,我建议您为派系和技能创建类而不是枚举。这样你就能够改变它们。

A brief OOPs class to begin with --
The Faction and Skill entities seem to have a has a relationship i.e., A Factions HAS A set of Skills. Also I will create an additional enum SkillName which again has a HAS A relation ship with Skill. So keeping these in mind you could arrange you enums like so --

public enum Faction {
    FACTION1(new HashMap<SkillName, Skill>(){{
        put(Skill.SNIPER_SHOT.skillName(), Skill.SNIPER_SHOT);
    }}),
    FACTION2(new HashMap<SkillName, Skill>(){{
        put(Skill.JUDGEMENT.skillName(), Skill.JUDGEMENT);
    }});

     Map<SkillName, Skill> skills;
    Faction(Map<SkillName, Skill> skills) {
        this.skills = skills;
    }

    public Skill[] skills(){
        return this.skills.values().toArray(new Skill[0]);
    }

    public Skill skill(SkillName name){
        Skill skill =  this.skills.get(name);
        if(Objects.isNull(skill)){
            throw new IllegalArgumentException("Invalid Skill name");
        }
        return skill;
    }

}

enum SkillName {
    SNIPER_SHOT("SNIPER_SHOT"),
    JUDGEMENT("JUDGEMENT");
    String value;

    SkillName(String value){
        this.value = value;
    }

}

enum Skill {
    SNIPER_SHOT(SkillName.SNIPER_SHOT, 0, 95, 5, new boolean[] {true, true, false, false}, new boolean[] {false, true, true, true}),
    JUDGEMENT(SkillName.JUDGEMENT,-25, 85, 5, new boolean[] {true, true, false, false}, new boolean[] {true, true, true, true});
    SkillName name;
    Integer dmg;
    Integer acc;
    Integer crit;
    boolean[] rank;
    boolean[] target;
    Skill(SkillName name, Integer dmg, Integer acc, Integer crit, boolean[] rank, boolean[] target) {
        this.name = name;
        this.dmg = dmg;
        this.acc = acc;
        this.crit = crit;
        this.rank = rank;
        this.target = target;
    }

    public SkillName skillName() {
        return this.name;
    }
}

Now you could access the skills and a specific skill like so, --

Faction.FACTION1.skills();
Faction.FACTION2.skills();
Faction.FACTION1.skill(SkillName.SNIPER_SHOT);
Faction.FACTION1.skill(SkillName.JUDGEMENT); // this should throw exception
Faction.FACTION2.skill(SkillName.SNIPER_SHOT); // this should throw exception
Faction.FACTION2.skill(SkillName.JUDGEMENT);

The access patterns are not exactly the same as you wanted, but these work pretty much to the same extent.

SIDE NOTE -

Not sure what type of game you are developing, but in most of the games, skill of players improve (i.e. skill properties change) and players acquire new skills as well. Hence the above setup will become very rigid as enums are immutable and you will not be able to scale this. Instead, what I would suggest is that you create classes for Factions and Skills instead of enums. This way you would be able to mutate them.

负佳期 2025-01-22 03:37:37

刚刚决定升级到 Java 9 以使用 Map.of()。谢谢大家的帮助!

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

孤独岁月 2025-01-22 03:37:37

看起来您已经找到了解决方案,但这里有一些可能更容易使用的东西。

import java.util.Arrays;
import java.util.List;

/** Enums. https://stackoverflow.com/questions/71517372 */
public class SOQ_20220406_0201
{

   /**
    * 
    * Main method.
    * 
    * @param   args  commandline arguments, should they be needed.
    * 
    */
   public static void main(String[] args)
   {
   
      enum Faction
      {
      
         F1,
         F2,
         F3,
         ALL,
         ;
      
      }
      
      enum Skill
      {
      
         SKILL_1(Faction.F1, "arbitraryArgs"),
         SKILL_2(Faction.F2, "arbitraryArgs"),
         SKILL_3(Faction.F3, "arbitraryArgs"),
         SKILL_ALL_CAN_USE(Faction.ALL, "arbitraryArgs"),
         ;
         
         private final Faction faction;
         private final String arbitraryArgs;
         
         Skill(Faction faction, String arbitraryArgs)
         {
         
            this.faction = faction;
            this.arbitraryArgs = arbitraryArgs;
         
         }
         
         public static List<Skill> fetchAllSkillsForFaction(final Faction faction)
         {
         
            return
               Arrays.stream(values())
                  .parallel()
                  .filter(each -> each.faction == faction)
                  .toList()
                  ;
         
         }
      
      }
      
      System.out.println(Skill.fetchAllSkillsForFaction(Faction.F1));
   
   }

}

Seems like you already found your solution, but here is something that is probably much easier to use.

import java.util.Arrays;
import java.util.List;

/** Enums. https://stackoverflow.com/questions/71517372 */
public class SOQ_20220406_0201
{

   /**
    * 
    * Main method.
    * 
    * @param   args  commandline arguments, should they be needed.
    * 
    */
   public static void main(String[] args)
   {
   
      enum Faction
      {
      
         F1,
         F2,
         F3,
         ALL,
         ;
      
      }
      
      enum Skill
      {
      
         SKILL_1(Faction.F1, "arbitraryArgs"),
         SKILL_2(Faction.F2, "arbitraryArgs"),
         SKILL_3(Faction.F3, "arbitraryArgs"),
         SKILL_ALL_CAN_USE(Faction.ALL, "arbitraryArgs"),
         ;
         
         private final Faction faction;
         private final String arbitraryArgs;
         
         Skill(Faction faction, String arbitraryArgs)
         {
         
            this.faction = faction;
            this.arbitraryArgs = arbitraryArgs;
         
         }
         
         public static List<Skill> fetchAllSkillsForFaction(final Faction faction)
         {
         
            return
               Arrays.stream(values())
                  .parallel()
                  .filter(each -> each.faction == faction)
                  .toList()
                  ;
         
         }
      
      }
      
      System.out.println(Skill.fetchAllSkillsForFaction(Faction.F1));
   
   }

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文