如何使用基类对静态关系数据进行硬编码?

时间:2017-08-03 14:17:08

标签: java database enums static hardcode

在我的应用程序中,我需要访问一些"关系"运行时的数据。如果我有大量数据或经常更改,我会将其存储在数据库(sqlite或其他东西)中。但我只有几个具有5-50个对象的实体,这些实体不会发生变化(通常)并且仅由开发人员改变。因此,我认为简单地对Java类中的数据进行硬编码以实现更简单的代码维护是有意义的。

所有实体共享一个共同的抽象超类(具有int idString name)。 在定义数据之后,我想要引用每个实体对象和一个Collection / Array,所有这些对象都可以在类之外使用。 我想确保数据是不可变的。

第一个想法是做这样的事情:

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中。这让我很烦。它是一种冗余和错误来源。

然后我想到使用枚举作为实体类,我可以在其中定义权利对象,并隐含地在values()数组中引用对象引用。 但由于具有基类(AbstractEntity)并且Java中无法实现多重继承,因此无法工作。

下一个想法是,使用具有默认方法的接口而不是抽象基类,并且实体定义实现此接口的枚举。 但是,我不能在基类(接口)中定义int id和String name,并且必须在每个子类中定义它。

我缺少一些语法糖吗? 这里的最佳做法是什么?

2 个答案:

答案 0 :(得分:1)

这样的事情可以通过反射来实现。

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 )应该是直截了当的。

答案 1 :(得分:1)

正如评论中所解释的,我宁愿使用Enum来存储每个实体的实例。您可以向枚举构造函数添加参数,以便您可以实例化并存储实体值。

接下来,我为您提供了一个解决方案,让您的Set存储所有实例,Enum表示A类实体,另一个表示B类实体(均来自{{在ALL集中使用的1}}。 ALL集合填充在从ENUMS检索值的静态部分上,因此,您只需在枚举上添加条目以添加新值。

<强> Entities.java

AbstractEntity

<强> AbstractEntity.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");
            }
        }
    }
}

<强> MyEntityA.java 公共最终类MyEntityA扩展了AbstractEntity {

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();

}

}

<强> MyEntityB.java 公共最终类MyEntityB扩展了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
}

}

请注意:

  • 如果您愿意,可以使用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
  • 我添加了一个主要的测试方法,但您也可以删除它。