在java中更新ENUM的值

时间:2017-12-20 06:49:54

标签: java design-patterns enums

我有一个 ENUM ,我在应用程序初始化时从数据库更新这些枚举值。然后使用enum all-over应用程序。

这样做的原因是,如果Value需要从数据库更改,那么只需在属性表中添加该值并更新它,以便在初始化枚举值得到更新时,其他枚举默认值将起作用。

示例: 我有这个枚举:

public enum Planet {
    MERCURY (3.303e+23, 2.4397e6),
    VENUS   (4.869e+24, 6.0518e6),
    EARTH   (5.976e+24, 6.37814e6);

    private final double mass;   // in kilograms
    private final double radius; // in meters
    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
    }
    private double mass() { return mass; }
    private double radius() { return radius; }

    private void setMass(double mass) { this.mass = mass; }
    private void setRadius(double radius) { this.radius = radius; }

}

我用set方法更新Enum的值。

我想知道这样做是否正确。这种情况的正确方法是什么?

4 个答案:

答案 0 :(得分:2)

Java enums mutability usecases and possibilities?

我不建议你让枚举值可变,它们应该几乎总是最终确定。

答案 1 :(得分:2)

枚举常量是单例,不可变对象可以在整个应用程序中使用massradius 根据数据库更新,无法动态更改字段。

相反,可以创建内存缓存来存储massradius值,并且可以在每次数据库更新时刷新此内部Map。但是,如果您需要使应用程序更具可伸缩性,那么您必须使用外部缓存(如Redis)来存储PlanetStats对象,而不是内部Map

enum Planet {
    MERCURY,
    VENUS,
    EARTH
}

class PlanetStats {
    private final double mass;
    private final double radius;

    PlanetStats(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
    }

    public double getMass() {
        return mass;
    }

    public double getRadius() {
        return radius;
    }
}


class PlanetCache {

    private final Map<Planet, PlanetStats> stats = new ConcurrentHashMap<>();

    // can be invoked on database update for each Planet object change
    public void refresh(Planet planet, PlanetStats planetStats) {
        stats.put(planet, planetStats);
    }

    // can be invoked to fetch PlanetStats for specified Planet
    public PlanetStats getPlanetStats(Planet planet) {
        return stats.get(planet);
    }
}

答案 2 :(得分:1)

对于使用setter的更新,字段不应为final

就是这样。其他论点没有实际意义。如果你有一个最终的命名值范围,枚举就可以了。

immutable 类(带有final字段)本来会更好,但是除非使用静态初始化,否则数据库无法实现。在初始化期间需要数据库可能是可以接受的,但通常应尽可能避免,并且当它不是嵌入式数据库时。

答案 3 :(得分:0)

即使你可以改变枚举的状态 - 我也不推荐它。

枚举是单身,这意味着

  1. 您的状态更改应该是线程安全的,因为一个线程可能会使用枚举,而另一个线程会更改它的状态。

  2. 状态未像其他对象的状态那样被序列化。如果你使用序列化,直接或通过其他框架或技术,如RMI或spring remoting,状态更改将无法正常工作。

    E.g。

    public static void main(String[] args) {
        Planet mercury = Planet.MERCURY;
    
        mercury.setMass(1.0);
    
        byte[] mercurySerialized = SerializationUtils.serialize(mercury);
    
        mercury.setMass(2.0);
    
        Planet mercuryDeserialized = SerializationUtils.deserialize(mercurySerialized);
    
        System.out.println(mercuryDeserialized.mass());
    }
    

    打印

    2.0
    

    反序列化Planet的质量属性不具有Planet序列化时的值。

    我也在序列化旁路部分的Singleton implementation pitfalls博客中讨论了此问题。

  3. PS:我使用了来自commons-lang3的SerializationUtils