使用大量已实现的接口

时间:2018-02-19 00:53:21

标签: java

我正在尝试创建一个涉及机器和物品的游戏。我有一个简单的项目界面,每个项目都将实现这一点。

我通常只会为每个项目创建一个类,但可能会有数千个项目,并且为所有项目创建数千个文件感觉不对。这适用于我可能拥有的其他大量类型的对象。 (地砖,实体)

我需要一种类型安全的方式来存储所有这些实现的接口。我需要能够轻松地在我的代码中创建一个新项目,只有项目的名称。

我在想有一个庞大的类,其子类包含许多最终常量,这些常量都是匿名类,但这似乎也是一种不好的方法。

有没有什么好方法可以做我的想法? (对不起,这有点模糊)

我的项目界面目前是

package com.bobona.craftable.model;

import com.bobona.craftable.CraftableGame;

import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

public interface Item {

    String getId();
    Map<String, Integer> getValues();
    void onUse(AtomicReference<CraftableGame> game, Long entityUsedByIndex);
    void onSecondaryUse(AtomicReference<CraftableGame> game, Long 
    entityUsedByIndex);
}

3 个答案:

答案 0 :(得分:3)

在开始编码任何内容之前,您需要先考虑游戏的层次结构

你还没有描述过这个游戏的任何内容,比如它里面的内容或者对象是什么,或者什么东西可以与什么相关联,所以我将描述一个我喜欢的流行游戏 - Factorio

在这个游戏中,在其他事物中,有一些事情需要描述:

  • 允许您制作其他物品的物品
  • 移动物品的腰带
  • 将项目转换为其他项目的汇编程序

所以我首先要描述这些事物如何相互作用的基本层次结构。

  • 用于项目的类,以及允许我们描述项目是什么以及我们如何与其交互的枚举(如果它是否可以制作,这是组装者拥有的规则)
  • 皮带类,我们想要支持的皮带类型(现在游戏有3种)
  • 汇编程序的一个类,它描述了一次可以接受多少项以及它们制作速度有多快

在描述规则之前,您必须了解项目与环境的交互方式。例如:

  • 可以通过插入器将物品放在皮带上。
  • 可以通过使用插入器将项目放入汇编程序。

这需要您更多考虑。但是,只要世界上只有少数几个元素,你应该拥有的课程数量会很少。

答案 1 :(得分:2)

  

通常只会为每个项目创建一个类,但可能会有数千个项目,并且为所有项目创建数千个文件感觉不对。

是的,你不应该这样做。类充当对象的蓝图。我们不为每个新对象创建一个新类。如果您发现所有商品都共享一个公共属性(例如name),那么这些属性可以用作基类的属性:

public abstract class Entity{
    protected String name;
    public Entity(String name){
        this.name = name;
    }
}

然后对于那些作为Item的对象,可以将它扩展到基类:

//example
public abstract class Monster extends Entity{
    protected int damage;
    //constructor not shown
}

如果您还需要指明实体是Ground还是Air。您也可以使用Interface:

public Interface OnAir{
}

public Interface OnGround{
}

然后你可以:

//example
public class FlyingMonster extends Monster implements OnAir {
    //your other attributes here
}
public class LandMonster extends Monster implements OnGround {
    //your other attributes here
}

现在,您可以灵活地操纵所需的对象类型。

存储所有怪物(地面和空中):

ArrayList<Monster> monsters = new ArrayList<>();

存储包括怪物在内的所有实体:

ArrayList<Entity> entities= new ArrayList<>();

以上解决方案是回复您的问题。但是,我应该提到在游戏制作中,我不想创建那么多类。但相反,我会将所有实体存储在数据文件中。如果您的实体有特殊属性。例如,一种基于火焰的武器,对所有以冰为基础的作物造成30%的额外伤害。我也不会用Java编写代码。而是将其存储在脚本文件中。然后,基于火力的武器将被引用到脚本文件中。

同样的逻辑适用于您的不可播放角色。

那么将它们存储在脚本和数据文件中有什么好处?您可以添加/删除/编辑实体,而无需重新编译代码。您可以更改武器的工作方式,角色的行为方式,NPC如何在不改变Java的情况下进行通话。

这意味着您现在可以通过输入文本文件将新项目添加到游戏中。

答案 2 :(得分:2)

这是一个困难的设计问题,据我所知,没有一个尺寸适合所有答案。正如Makoto在另一个答案中所提到的,你的大部分方法将取决于你特定游戏的实际细节。

  

我通常会为每个项目创建一个类,但可能会有数千个项目,并且为所有项目创建数千个文件感觉不对。

我完全同意这句话。

  

我需要一种类型安全的方式来存储所有这些实现的接口。

如果我们接受先前声明单独的类或接口不是正确的方法,我不确定这是否可行(字面意思是如此)。但是,如果不是类型安全,你会在运行时通过一些尚未指定的机制来解决可验证的问题,那么我认为这是非常可行的。

  

[来自评论]使用非类型安全值来定义食谱中的项目也不是很好,因为这很快会成为调试和重构的痛苦。

我同意你需要某种验证,但如前所述,完整的编译时类型安全可能不可行,同时也避免了数千个单独的类。我认为这里的关键是可靠地检测错误,以不破坏游戏的方式响应错误,并为开发人员生成合理的调试消息。

有很多方法可以实现这一目标;您选择哪一个取决于您的确切要求,您的偏好以及我无从知晓的一些实施细节。我认为您应该考虑或考虑的一些事情:

  • 由于您已经识别的原因,继承可能根本不起作用。
  • 作文或flyweight pattern最初可能会有所改善,但probably won't scale the way you want
  • 您可以采用RDBMS方法,outlined here
  • 您可以尝试使用基于JSON的方法或等效方法,如outlined here
  • component pattern非常符合我对您问题的理解。
  • This是一个写得非常好的答案,详细说明了如何使用位字段实现实体的组件模式(我认为包括您所描述的项目类型)。
  • This是一个非常类似的问题,你可以在gamedev stackexchange上找到一些很好的答案。

我个人喜欢组件模式,并且喜欢使用JSON或等效语言来指定项目本身。希望至少上述一些信息可以帮助您迭代修改架构以满足您的游戏需求。