[英]How can I simulate Enums that can be expanded at Runtime in Java?
我正在編寫一個程序,從一個名為《文明4》的游戲中模擬城市。為此,我使用了多個枚舉來表示該城市擁有的每個地塊的地形類型,資源,改善情況等。
問題是我想編程以與Fan made mods兼容,這可能會增加游戲中需要被我獨立的工具接受的東西。 所以我想到了創建一個Enum 樣式類來容納由加載的mod定義的新類型(因為Enums在運行時無法更改),該類型是在運行時在用戶輸入要加載的mod時創建的(這是一個txt文件,被解析以讀取新添加的內容)
那么,有沒有一種方法可以模擬在運行時創建並添加到的枚舉? 我認為靜態成員變量無法使用,因為它們在運行時之前就已完成...
您可以使enum
實現接口。
這樣,您可以在枚舉中包含定義的值,但是新值可以是實現該接口的任何類。
另一種選擇是在運行時使用字節碼生成器或Compiler API生成或加載enum
。 我編寫了一個庫,以使其更容易采用String並進行編譯和加載。
嗯,Java中的枚舉只是類,在該類中,語言保證了已知對象的集合在編譯時是已知的並且受到限制。 如果要在運行時添加新的枚舉常量,則需要使用常規類。
枚舉的優點在於,您可以在代碼中編寫人類可讀的名稱,這些名稱在幕后編譯為數字,因為計算機更喜歡數字。 以這個枚舉為例:
enum Season { WINTER, SPRING, SUMMER, AUTUMN }
在幕后WINTER可能為0(零),SPRING為1等。要在運行時代碼中復制此行為,可以創建一個字符串列表,如下所示:
List<String> seasons;
seasons = new ArrayList<String>();
seasons.add("Winter");
seasons.add("Spring");
...
這樣,您可以將項目引用為數字,例如seasons [1]等於“ Spring”。 這個答案只是解決這個問題的多種方式之一。
默認情況下, enum
類型只有一組設定的值。 enum
類型中的值實際上被聲明為static final
,並且無法在運行時添加更多值。
話雖這么說,您還可以使用其他模式來實現所需的功能。 讓我們看一下使用界面和注冊系統。 我們將從Terrain
界面開始:
public interface Terrain {
int getId();
String getName();
int getSightBonus();
}
現在是一個enum
, DefaultTerrain
:
public enum DefaultTerrain implements Terrain {
PLAINS(0, "Plains", 1),
HILLS(1, "Hills", -1),
MOUNTAINS(2, "Mountains", -2);
private int id;
private String name;
private int sightBonus;
private DefaultTerrain(int id, String name, int sightBonus) {
this.id = id;
this.name = name;
this.sightBonus = sightBonus;
}
public int getId() {return id;}
public String getName() {return name;}
public int getSightBonus() {return sightBonus;}
}
還有一個注冊類,它可以是靜態實用程序類或單例。
public class TerrainManager {
private static Map<Integer, Terrain> terrainsById = new HashMap<>();
static {
for (DefaultTerrain terrain : DefaultTerrain.values())
register(terrain);
}
public static void register(Terrain terrain) {
Integer id = terrain.getId();
if (terrainsById.contains(terrain.getId()))
throw new IllegalArgumentException("Terrain with id already exists: " + id);
terrainsById.put(id, terrain);
}
public static Terrain getTerrainById(int id) {
return terrainsById.get(id);
}
public static Set<Terrain> getAllTerrains() {
return new HashSet<Terrain>(terrainsById.values());
}
}
最后一節課是魔術發生的地方。 大概這些修改者在游戲的世界定義中會有某種標識符,說“使用此圖塊”,對嗎? 在這種情況下,我將其稱為整數id
,但實際上它可以是任何類型,只需相應地修改Map
。 在加載地圖的代碼中,只需使用世界定義中的ID即可查找Terrain
。 當修改器添加新的Terrain
,他們只需要實現Terrain
並將其注冊到TerrainManager
。
static
初始化程序確保在添加任何其他內容之前先添加DefaultTerrain
對象。 如果使用單例,則可以將其放入類構造函數中。
將此模式用於要用戶添加到的不同enum
類型。 除了enum
您還可以將其用於幾乎所有其他類型。
您將需要CGLIB, http://cglib.sourceforge.net/
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.