Java Enumerations - Choosing Between Fields, Abstract Methods, and a Level Map

I wrote a Java enumeration where values ​​have different attributes. These attributes can be stored in one of the following ways:

Using fields:

enum Eenum { V1(p1), V2(p2); private final A attr; public A attr() { return attr; } private Eenum(A attr) { this.attr = attr; } } 

Using abstract methods:

 enum Eenum { V1 { public A attr() { return p1; } }, V2 { public A attr() { return p2; } } public abstract A attr(); } 

Using a level card:

 enum Eenum { V1, V2; public A attr() { return attrs.get(this); } private static final Map<A> attrs; static { ImmutableMap.Builder<Eenum, A> builder = ImmutableMap.builder(); builder.put(V1, p1); builder.put(V2, p2); attrs = builder.build(); } } 

How do I decide when to choose which one?

Thanks!

+6
source share
3 answers

(I answer my question to share some things that I learned when they tried to find things.)

Here are the questions you must ask in order to arrive at a solution for your specific case:

1: do attribute values ​​contain links to direct links?

Sometimes V1 may require a reference to V2 and vice versa. This is not a rare case. If you are dealing with such an enum , approach 1 just won't work. The compiler (rightfully) will complain about illegal direct links. You can use either of the other two approaches.

Now, if the attribute value is computationally expensive and constant, you want it to be evaluated only once. With approach 2, you will need to enter local variables for the enum value and caching results. This is verbose, but will give you better performance. With approach 3, in any case, the results are calculated only once, and therefore no additional work needs to be done. This is more readable, but slightly less effective than approach 2. Design between them in accordance with the specific compromises guaranteed in your case.

2: Do I need to cache the results?

Refer to the second paragraph of the previous bullet.

If there are no direct links, you can also use approach 1. But if the calculation involved in the calculation of the attributes is complicated, you are better off with one of the other two approaches.

3: Do attributes match all enumeration values?

If not, then it is only logical that you should use Map here. That is, approach 3.

4: Are there default values ​​for some attributes for some enum values?

If so, you can use all three approaches, and they all offer different combinations of compromises.

With approach 1: you must define a helper constructor that initializes the attribute with a default value. If several such attributes exist, this may not be practical.

With Approach 2: This will be like the “fourth” approach proposed by Peter Laurie. You will have a method that returns the default value in the main enum tag. And some enumeration values ​​override this method to return a different value. This, again, is pretty verbose.

With approach 3: Less effective. Good in a different way.

0
source

I would do the one that you think is the easiest.

In general, I do not write code that can be implemented using data. I would use the first one.

In my actual use case, there are some attributes that do not apply to all enumeration values

You can use a combination of these approaches if it makes sense based on each attribute.

The fourth option is to not have an abstract method.

 enum Eenum { V1 { public A attr() { return p1; } }, V2 { public A attr() { return p2; } }, V3, V4, V5, V6; public A attr() { return defaultA; } } 
+3
source

Nothing out of this. Do it:

 interface HasAttr<T> { T attr(); } enum Eenum implements HasAttr<A> { // use "fields" version - ideally with constructor version public A attr() { return field; } } 

This pattern follows the basic Abstract Type design pattern, which allows you to use this method:

 public void someMethod(HasAttr<A> hasAttr); // pass anything that is HasAttr<a> 

instead of a fixed type:

 public void someMethod(Eenum eenum); // locked into passing an Eenum 

Also, and, more importantly, it’s easier to test, especially if your listing uses real joins, etc.

I give you, all this applies only if the listing is "non-trivial." If this is just a regular old enumerator, I agree that this is just a bloat code (which I also hate)

0
source

All Articles