如何使用 base class 硬编码静态关系数据?
How to hard-code static relational data with base class?
在我的应用程序中,我需要在运行时访问一些 "relational" 数据。如果我有很多数据或者它经常更改,我会将它存储在数据库(sqlite 或其他东西)中。但我只有几个实体,其中包含 5-50 个对象,这些对象不会(经常)更改,并且会由开发人员单独更改。所以我认为简单地硬编码 Java classes 中的数据以简化代码维护是有意义的。
所有实体共享一个公共抽象超级class(有一个int id
和一个String name
)。
定义数据后,我想引用每个实体对象和 Collection/Array 所有这些对象都在 class 之外可用。
我想确保数据是不可变的。
第一个想法是做这样的事情:
public abstract class AbstractEntity{
private final int id;
private String name;
protected AbstractEntity(int id, String name){
this.id = id;
this.name = name;
}
private void someMethods(){
...
}
abstract protected void someAbstractMethods(){
...
}
}
public final class MyEntity extends AbstractEntity{
public static final ENTITY_1 = new MyEntity(1, "Entity 1", "foo");
public static final ENTITY_2 = new MyEntity(2, "Entity 2", "bar");
public static final ENTITY_3 = new MyEntity(3, "Entity 3", "baz");
public static final Set<MyEntity> ALL = Collections.unmodifiableSet(new TreeSet<>(Arrays.asList(ENTITY_1, ENTITY_2, ENTITY_3)));
private final String foo;
private MyEntity(int id, String name, String foo){
super(id, name);
this.foo = foo;
}
}
我看到的缺陷是,在开发过程中添加新实体时,我也必须将它添加到 ALL Set 中。这让我很烦。这是一种冗余和错误来源。
然后我只是想使用枚举作为实体 classes,我可以在其中定义实体对象并在 values() 数组中隐含地引用所有对象。
但这不起作用,因为有一个基础 class (AbstractEntity) 并且在 Java.
中不可能进行多重继承
下一个想法是使用具有默认方法的接口,而不是抽象基础 class,并且作为实体定义一个实现该接口的枚举。
但是那样我就无法在基础 class (接口)中定义 int id 和 String name 并且必须在每个 subclass.
中定义它
我是否缺少一些语法糖?
这里的最佳做法是什么?
像这样的事情可以使用反射来解决问题。
public final class MyEntity extends AbstractEntity{
public static final ENTITY_1 = new MyEntity(1, "Entity 1", "foo");
public static final ENTITY_2 = new MyEntity(2, "Entity 2", "bar");
public static final ENTITY_3 = new MyEntity(3, "Entity 3", "baz");
public static final Set<MyEntity> ALL;
static {
final Set<MyEntity> all = new TreeSet<>();
// Find all static fields in this class which are instances of this class:
final Field[] fields = MyEntity.class.getDeclaredFields();
for ( Field f : fields ) {
if ( f.getType() == MyEntity.class ) {
if ( Modifier.isStatic( f.getModifiers() ) {
all.add((MyEntity)f.get(null));
}
}
}
ALL = Collections.unmodifiableSet( all );
}
private final String foo;
private MyEntity(int id, String name, String foo){
super(id, name);
this.foo = foo;
}
}
从中编写通用效用函数 initializeEntitySet( Class<?> entityClass )
应该很简单。
如评论中所述,我宁愿使用 Enum
来存储每个实体的实例。您可以向枚举构造函数添加参数,以便随后实例化和存储实体值。
接下来,我为您提供一个解决方案,让您的 Set
存储所有实例,并使用 Enum
用于 A 类型的实体,另一个用于 B 类型的实体(均继承自AbstractEntity
用于 ALL 集合)。 ALL 集合填充在从 ENUMS 检索值的静态部分,因此,您只需在枚举上添加条目即可添加新值。
Entities.java
public class Entities {
// Entities of class A
private enum EntitiesOfA {
ENTITY_A_1(1, "EntityA 1", "foo"), // A1
ENTITY_A_2(2, "EntityA 2", "bar"), // A2
ENTITY_A_3(3, "EntityA 3", "baz"); // A3
private MyEntityA entity;
private EntitiesOfA(int id, String name, String foo) {
this.entity = new MyEntityA(id, name, foo);
}
public MyEntityA getEntity() {
return this.entity;
}
}
// Entities of class B
private enum EntitiesOfB {
ENTITY_B_1(4, "EntityB 1", 10), // B1
ENTITY_B_2(5, "EntityB 2", 11), // B2
ENTITY_B_3(6, "EntityB 3", 12); // B3
private MyEntityB entity;
private EntitiesOfB(int id, String name, int value) {
this.entity = new MyEntityB(id, name, value);
}
public MyEntityB getEntity() {
return this.entity;
}
}
// All Entities
public static final Set<AbstractEntity> ALL;
static {
// I use HashSet instead of TreeSet because I have
// not implemented the comparable interface
Set<AbstractEntity> allEntities = new HashSet<>();
for (EntitiesOfA entity : EntitiesOfA.values()) {
allEntities.add(entity.getEntity());
}
for (EntitiesOfB entity : EntitiesOfB.values()) {
allEntities.add(entity.getEntity());
}
ALL = Collections.unmodifiableSet(allEntities);
}
public static void main(String[] args) {
for (AbstractEntity entity : ALL) {
System.out.println("Entity ID = " + entity.getId() + " NAME = " + entity.getName());
entity.someAbstractMethods();
if (entity instanceof MyEntityA) {
MyEntityA a = (MyEntityA) entity;
System.out.println("Entity A with foo = " + a.getFoo());
a.someMethods();
} else if (entity instanceof MyEntityB) {
MyEntityB b = (MyEntityB) entity;
System.out.println("Entity B with value = " + b.getValue());
b.someMethods();
} else {
System.err.println("ERROR: Unrecognised subclass");
}
}
}
}
AbstractEntity.java
public abstract class AbstractEntity {
private final int id;
private String name;
protected AbstractEntity(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return this.id;
}
public String getName() {
return this.name;
}
public void someMethods() {
// A
}
protected abstract void someAbstractMethods();
}
MyEntityA.java
public final class MyEntityA extends AbstractEntity {
private final String foo;
public MyEntityA(int id, String name, String foo) {
super(id, name);
this.foo = foo;
}
public String getFoo() {
return this.foo;
}
@Override
protected void someAbstractMethods() {
// Some code
}
}
MyEntityB.java
public 最终 class MyEntityB 扩展了 AbstractEntity {
private final int value;
public MyEntityB(int id, String name, int value) {
super(id, name);
this.value = value;
}
public int getValue() {
return this.value;
}
@Override
protected void someAbstractMethods() {
// Some code
}
}
注意:
如果您愿意,ENUM 中的构造函数可以替换为 VAL(new MyEntityA(...))
。在这种情况下,您可以合并 EntitesOfA
和 EntitesOfB
以拥有所有实体并使用带有 AbstractEntity
的构造函数。您也可以删除 Set
。
public class AllEntities {
private enum Entities {
ENTITY_A_1(new MyEntityA(1, "EntityA 1", "foo")), // A1
ENTITY_A_2(new MyEntityA(2, "EntityA 2", "bar")), // A2
ENTITY_A_3(new MyEntityA(3, "EntityA 3", "baz")), // A3
ENTITY_B_1(new MyEntityB(4, "EntityB 1", 10)), // B1
ENTITY_B_2(new MyEntityB(5, "EntityB 2", 11)), // B2
ENTITY_B_3(new MyEntityB(6, "EntityB 3", 12)); // B3
private AbstractEntity entity;
private Entities(AbstractEntity entity) {
this.entity = entity;
}
public AbstractEntity getEntity() {
return this.entity;
}
}
// All Entities
public static final Set<AbstractEntity> ALL;
static {
// I use HashSet instead of TreeSet because I have
// not implemented the comparable interface
Set<AbstractEntity> allEntities = new HashSet<>();
for (Entities entity : Entities.values()) {
allEntities.add(entity.getEntity());
}
ALL = Collections.unmodifiableSet(allEntities);
}
我添加了一个用于测试的主要方法,但您也可以将其删除。
在我的应用程序中,我需要在运行时访问一些 "relational" 数据。如果我有很多数据或者它经常更改,我会将它存储在数据库(sqlite 或其他东西)中。但我只有几个实体,其中包含 5-50 个对象,这些对象不会(经常)更改,并且会由开发人员单独更改。所以我认为简单地硬编码 Java classes 中的数据以简化代码维护是有意义的。
所有实体共享一个公共抽象超级class(有一个int id
和一个String name
)。
定义数据后,我想引用每个实体对象和 Collection/Array 所有这些对象都在 class 之外可用。
我想确保数据是不可变的。
第一个想法是做这样的事情:
public abstract class AbstractEntity{
private final int id;
private String name;
protected AbstractEntity(int id, String name){
this.id = id;
this.name = name;
}
private void someMethods(){
...
}
abstract protected void someAbstractMethods(){
...
}
}
public final class MyEntity extends AbstractEntity{
public static final ENTITY_1 = new MyEntity(1, "Entity 1", "foo");
public static final ENTITY_2 = new MyEntity(2, "Entity 2", "bar");
public static final ENTITY_3 = new MyEntity(3, "Entity 3", "baz");
public static final Set<MyEntity> ALL = Collections.unmodifiableSet(new TreeSet<>(Arrays.asList(ENTITY_1, ENTITY_2, ENTITY_3)));
private final String foo;
private MyEntity(int id, String name, String foo){
super(id, name);
this.foo = foo;
}
}
我看到的缺陷是,在开发过程中添加新实体时,我也必须将它添加到 ALL Set 中。这让我很烦。这是一种冗余和错误来源。
然后我只是想使用枚举作为实体 classes,我可以在其中定义实体对象并在 values() 数组中隐含地引用所有对象。 但这不起作用,因为有一个基础 class (AbstractEntity) 并且在 Java.
中不可能进行多重继承下一个想法是使用具有默认方法的接口,而不是抽象基础 class,并且作为实体定义一个实现该接口的枚举。 但是那样我就无法在基础 class (接口)中定义 int id 和 String name 并且必须在每个 subclass.
中定义它我是否缺少一些语法糖? 这里的最佳做法是什么?
像这样的事情可以使用反射来解决问题。
public final class MyEntity extends AbstractEntity{
public static final ENTITY_1 = new MyEntity(1, "Entity 1", "foo");
public static final ENTITY_2 = new MyEntity(2, "Entity 2", "bar");
public static final ENTITY_3 = new MyEntity(3, "Entity 3", "baz");
public static final Set<MyEntity> ALL;
static {
final Set<MyEntity> all = new TreeSet<>();
// Find all static fields in this class which are instances of this class:
final Field[] fields = MyEntity.class.getDeclaredFields();
for ( Field f : fields ) {
if ( f.getType() == MyEntity.class ) {
if ( Modifier.isStatic( f.getModifiers() ) {
all.add((MyEntity)f.get(null));
}
}
}
ALL = Collections.unmodifiableSet( all );
}
private final String foo;
private MyEntity(int id, String name, String foo){
super(id, name);
this.foo = foo;
}
}
从中编写通用效用函数 initializeEntitySet( Class<?> entityClass )
应该很简单。
如评论中所述,我宁愿使用 Enum
来存储每个实体的实例。您可以向枚举构造函数添加参数,以便随后实例化和存储实体值。
接下来,我为您提供一个解决方案,让您的 Set
存储所有实例,并使用 Enum
用于 A 类型的实体,另一个用于 B 类型的实体(均继承自AbstractEntity
用于 ALL 集合)。 ALL 集合填充在从 ENUMS 检索值的静态部分,因此,您只需在枚举上添加条目即可添加新值。
Entities.java
public class Entities {
// Entities of class A
private enum EntitiesOfA {
ENTITY_A_1(1, "EntityA 1", "foo"), // A1
ENTITY_A_2(2, "EntityA 2", "bar"), // A2
ENTITY_A_3(3, "EntityA 3", "baz"); // A3
private MyEntityA entity;
private EntitiesOfA(int id, String name, String foo) {
this.entity = new MyEntityA(id, name, foo);
}
public MyEntityA getEntity() {
return this.entity;
}
}
// Entities of class B
private enum EntitiesOfB {
ENTITY_B_1(4, "EntityB 1", 10), // B1
ENTITY_B_2(5, "EntityB 2", 11), // B2
ENTITY_B_3(6, "EntityB 3", 12); // B3
private MyEntityB entity;
private EntitiesOfB(int id, String name, int value) {
this.entity = new MyEntityB(id, name, value);
}
public MyEntityB getEntity() {
return this.entity;
}
}
// All Entities
public static final Set<AbstractEntity> ALL;
static {
// I use HashSet instead of TreeSet because I have
// not implemented the comparable interface
Set<AbstractEntity> allEntities = new HashSet<>();
for (EntitiesOfA entity : EntitiesOfA.values()) {
allEntities.add(entity.getEntity());
}
for (EntitiesOfB entity : EntitiesOfB.values()) {
allEntities.add(entity.getEntity());
}
ALL = Collections.unmodifiableSet(allEntities);
}
public static void main(String[] args) {
for (AbstractEntity entity : ALL) {
System.out.println("Entity ID = " + entity.getId() + " NAME = " + entity.getName());
entity.someAbstractMethods();
if (entity instanceof MyEntityA) {
MyEntityA a = (MyEntityA) entity;
System.out.println("Entity A with foo = " + a.getFoo());
a.someMethods();
} else if (entity instanceof MyEntityB) {
MyEntityB b = (MyEntityB) entity;
System.out.println("Entity B with value = " + b.getValue());
b.someMethods();
} else {
System.err.println("ERROR: Unrecognised subclass");
}
}
}
}
AbstractEntity.java
public abstract class AbstractEntity {
private final int id;
private String name;
protected AbstractEntity(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return this.id;
}
public String getName() {
return this.name;
}
public void someMethods() {
// A
}
protected abstract void someAbstractMethods();
}
MyEntityA.java public final class MyEntityA extends AbstractEntity {
private final String foo;
public MyEntityA(int id, String name, String foo) {
super(id, name);
this.foo = foo;
}
public String getFoo() {
return this.foo;
}
@Override
protected void someAbstractMethods() {
// Some code
}
}
MyEntityB.java public 最终 class MyEntityB 扩展了 AbstractEntity {
private final int value;
public MyEntityB(int id, String name, int value) {
super(id, name);
this.value = value;
}
public int getValue() {
return this.value;
}
@Override
protected void someAbstractMethods() {
// Some code
}
}
注意:
如果您愿意,ENUM 中的构造函数可以替换为
VAL(new MyEntityA(...))
。在这种情况下,您可以合并EntitesOfA
和EntitesOfB
以拥有所有实体并使用带有AbstractEntity
的构造函数。您也可以删除Set
。public class AllEntities { private enum Entities { ENTITY_A_1(new MyEntityA(1, "EntityA 1", "foo")), // A1 ENTITY_A_2(new MyEntityA(2, "EntityA 2", "bar")), // A2 ENTITY_A_3(new MyEntityA(3, "EntityA 3", "baz")), // A3 ENTITY_B_1(new MyEntityB(4, "EntityB 1", 10)), // B1 ENTITY_B_2(new MyEntityB(5, "EntityB 2", 11)), // B2 ENTITY_B_3(new MyEntityB(6, "EntityB 3", 12)); // B3 private AbstractEntity entity; private Entities(AbstractEntity entity) { this.entity = entity; } public AbstractEntity getEntity() { return this.entity; } } // All Entities public static final Set<AbstractEntity> ALL; static { // I use HashSet instead of TreeSet because I have // not implemented the comparable interface Set<AbstractEntity> allEntities = new HashSet<>(); for (Entities entity : Entities.values()) { allEntities.add(entity.getEntity()); } ALL = Collections.unmodifiableSet(allEntities); }
我添加了一个用于测试的主要方法,但您也可以将其删除。